diff --git a/core-kotlin-modules/core-kotlin-12/pom.xml b/core-kotlin-modules/core-kotlin-12/pom.xml
index e1572ace7..3202e2166 100644
--- a/core-kotlin-modules/core-kotlin-12/pom.xml
+++ b/core-kotlin-modules/core-kotlin-12/pom.xml
@@ -14,6 +14,21 @@
1.0.0-SNAPSHOT
+
+
+ io.kotest
+ kotest-runner-junit5
+ ${kotest.version}
+ test
+
+
+ io.kotest
+ kotest-property-jvm
+ ${kotest.version}
+ test
+
+
+
src/main/kotlin
src/test/kotlin
@@ -34,4 +49,10 @@
+
+
+ 5.9.0
+ 2.22.2
+
+
diff --git a/core-kotlin-modules/core-kotlin-12/src/main/kotlin/com/baeldung/formatting/NumberFormat.kt b/core-kotlin-modules/core-kotlin-12/src/main/kotlin/com/baeldung/formatting/NumberFormat.kt
new file mode 100644
index 000000000..b06711c01
--- /dev/null
+++ b/core-kotlin-modules/core-kotlin-12/src/main/kotlin/com/baeldung/formatting/NumberFormat.kt
@@ -0,0 +1,43 @@
+package com.baeldung.formatting
+
+import java.text.DecimalFormat
+import java.text.DecimalFormatSymbols
+import java.util.*
+
+/**
+ * Interface for the different formatting implementation.
+ */
+interface NumberFormat {
+
+ /**
+ * Returns provided number as string with thousands separator.
+ */
+ fun formatted(number: Int): String
+}
+
+object FormatByDecimalFormat : NumberFormat {
+ override fun formatted(number: Int): String =
+ DecimalFormat("#,###")
+ .format(number)
+ .replace(",", ".")
+}
+
+object FormatByDecimalFormatGermany : NumberFormat {
+ override fun formatted(number: Int): String =
+ DecimalFormat("#,###", DecimalFormatSymbols(Locale.GERMANY))
+ .format(number)
+}
+
+object FormatByStringFormat : NumberFormat {
+ override fun formatted(number: Int): String =
+ String.format(Locale.GERMANY, "%,d", number)
+}
+
+object FormatByChunking : NumberFormat {
+ override fun formatted(number: Int): String =
+ number.toString()
+ .reversed() // 15000 -> 00051
+ .chunked(3) // [000] [51]
+ .joinToString(".") // 000.51
+ .reversed() // 15.000
+}
diff --git a/core-kotlin-modules/core-kotlin-12/src/test/kotlin/com/baeldung/formatting/NumberFormatUnitTest.kt b/core-kotlin-modules/core-kotlin-12/src/test/kotlin/com/baeldung/formatting/NumberFormatUnitTest.kt
new file mode 100644
index 000000000..c99970104
--- /dev/null
+++ b/core-kotlin-modules/core-kotlin-12/src/test/kotlin/com/baeldung/formatting/NumberFormatUnitTest.kt
@@ -0,0 +1,50 @@
+package com.baeldung.formatting
+
+import io.kotest.core.spec.style.ShouldSpec
+import io.kotest.property.Arb
+import io.kotest.property.arbitrary.positiveInt
+import io.kotest.property.checkAll
+import org.assertj.core.api.Assertions.assertThat
+
+class NumberFormatUnitTest : ShouldSpec({
+
+ // Dynamic generation of tests for each implementation
+ nameToImplementationPairs.forEach { (name, function) ->
+
+ // Property based test (for each implementation)
+ should("return correctly formatted string with $name implementation") {
+ checkAll(Arb.positiveInt()) { number ->
+ var result = function(number)
+
+ assertThat(result).containsPattern("^(\\d{1,3}(\\.\\d{3})*|\\d+)$")
+ assertThat(number.toString()).isEqualTo(result.replace(".", ""))
+ }
+ }
+
+ givenToExpectedPairs.forEach { (givenNumber, expectedString) ->
+
+ // Parameterised; Example based test
+ should("return '$expectedString' for $givenNumber with $name implementation") {
+ assertThat(function(givenNumber)).isEqualTo(expectedString)
+ }
+ }
+
+ }
+})
+
+// Examples to check against, with given number and expected string
+private val givenToExpectedPairs = listOf(
+ 0 to "0",
+ 12 to "12",
+ 456 to "456",
+ 100_000 to "100.000",
+ 1_234_567 to "1.234.567"
+)
+
+// Different implementations of the formatting feature with the display name
+private val nameToImplementationPairs = listOf(
+ "FormatByChunking" to { it: Int -> FormatByChunking.formatted(it) },
+ "FormatByStringFormat" to { it: Int -> FormatByStringFormat.formatted(it) },
+ "FormatByDecimalFormatGermany" to { it: Int -> FormatByDecimalFormatGermany.formatted(it) },
+ "FormatByDecimalFormat" to { it: Int -> FormatByDecimalFormat.formatted(it) }
+)