From b728fca8091222599be694996e3b19f09be3c758 Mon Sep 17 00:00:00 2001 From: robbertvdzon Date: Sun, 8 May 2022 09:00:03 +0200 Subject: [PATCH] adding first set of tests: refactoring --- .../com/gildedrose/GildedRoseBaseTest.kt | 6 +- .../com/gildedrose/GildedRoseSulfurasTest.kt | 3 - .../gildedrose/RandomizedRegressionTest.kt | 111 +++++++++--------- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseBaseTest.kt b/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseBaseTest.kt index 369bb993..8ba49e77 100644 --- a/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseBaseTest.kt +++ b/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseBaseTest.kt @@ -36,7 +36,7 @@ abstract class GildedRoseBaseTest { testGildedRose(name, initialSellIn, initialQuality, numberDays, resultingSellIn, resultingQuality) } - fun testGildedRose( + private fun testGildedRose( name: String, initialSellIn: Int, initialQuality: Int, @@ -48,7 +48,7 @@ abstract class GildedRoseBaseTest { val items = arrayOf(item) val app = GildedRose(items) - (1..numberDays).forEach() { + (1..numberDays).forEach { _ -> app.updateQuality() } Assertions.assertThat(item.name).isEqualTo(name) @@ -56,7 +56,7 @@ abstract class GildedRoseBaseTest { Assertions.assertThat(item.quality).isEqualTo(resultingQuality) } - fun combinationsSource(): Stream = Stream.of(*combinationsToTest) + private fun combinationsSource(): Stream = Stream.of(*combinationsToTest) } \ No newline at end of file diff --git a/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseSulfurasTest.kt b/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseSulfurasTest.kt index 718faf3e..cec3fc45 100644 --- a/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseSulfurasTest.kt +++ b/Kotlin/src/test/kotlin/com/gildedrose/GildedRoseSulfurasTest.kt @@ -1,10 +1,7 @@ package com.gildedrose import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import java.util.stream.Stream @TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class GildedRoseSulfurasTest : GildedRoseBaseTest(){ diff --git a/Kotlin/src/test/kotlin/com/gildedrose/RandomizedRegressionTest.kt b/Kotlin/src/test/kotlin/com/gildedrose/RandomizedRegressionTest.kt index e480274c..d463bfbc 100644 --- a/Kotlin/src/test/kotlin/com/gildedrose/RandomizedRegressionTest.kt +++ b/Kotlin/src/test/kotlin/com/gildedrose/RandomizedRegressionTest.kt @@ -1,70 +1,75 @@ package com.gildedrose import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test import kotlin.random.Random -/* -TODO: - - const voor maxNrDays, MaxNrItems, MaxInitialQuality, MaxInitialQuality - - run als unit test, draai 1 minuut, of 1.000.000 keer - - comment: deze kan flaky zijn, maar bij 1.000.000 is die kans wel erg klein - - */ - -val productLists = listOf( +private const val NR_TESTS_TO_RUN = 100_000 // 100.000 random tests should be enough to cover any untested cases by the normal unit tests +private const val MAX_NR_ITEMS = 5 +private const val MAX_NR_DAYS = 100 +private const val MAX_INITIAL_QUALITY = 100 +private const val MIN_INITIAL_SELLIN = -10 +private const val MAX_INITIAL_SELLIN = 100 +private val PRODUCTS_LIST = listOf( "Aged Brie", "Sulfuras, Hand of Ragnaros", "Backstage passes to a TAFKAL80ETC concert", "Foo" ) +private val random = Random(System.currentTimeMillis()) -val random = Random(System.currentTimeMillis()) +class RandomizedRegressionTest { + @Test + fun `test random combinations and compare the result from the legacy code with the refactored code`() { + (0..NR_TESTS_TO_RUN).forEach{ + // create new random combination of items + val nrItemsToTest = random.nextInt(1,MAX_NR_ITEMS) + val nrDays = random.nextInt(1,MAX_NR_DAYS) + val initialItems = createRandomItemList(nrItemsToTest) + val legacyItems = initialItems.deepClone() + val refacturedItems = legacyItems.deepClone() + // clone the items for the legacy and the refactored implementation + val legacyApp = GildedRoseLegacy(legacyItems) + val refactoredApp = GildedRose(refacturedItems) -fun main(args: Array) { - (0..Int.MAX_VALUE).forEach(){ - val nrItemsToTest = random.nextInt(1,5) - val nrDays = random.nextInt(1,100) - val initialItems = createRandomItemList(nrItemsToTest) - val legacyItems = initialItems.deepClone() - val refacturedItems = legacyItems.deepClone() + // update the quality for a number of days for both the legacy and the refactored implementation + println("testing round $it, with $nrItemsToTest items and $nrDays days") + (1..nrDays).forEach { _ -> + legacyApp.updateQuality() + refactoredApp.updateQuality() + } - val legacyApp = GildedRoseLegacy(legacyItems) - val refactoredApp = GildedRose(refacturedItems) - - println("testing round $it, with $nrItemsToTest items and $nrDays days") - (1..nrDays).forEach { - legacyApp.updateQuality() - refactoredApp.updateQuality() + // compare the result of the legacy and the refactored implementation + val testDescription : String = describeTestcase(initialItems, nrDays, refactoredApp.items, legacyApp.items) + val actialItemsAsString = describeItems(refactoredApp.items) + val expectedItemsAsString = describeItems(legacyApp.items) + assertThat(actialItemsAsString).`as`("The following testcase failed: \n$testDescription").isEqualTo(expectedItemsAsString) } - - val testDescription : String = describeTestcase(initialItems, nrDays, refactoredApp.items, legacyApp.items) - val actialItemsAsString = describeItems(refactoredApp.items) - val expectedItemsAsString = describeItems(legacyApp.items) - assertThat(actialItemsAsString).`as`("The following testcase failed: \n$testDescription").isEqualTo(expectedItemsAsString) } + + private fun describeTestcase(initialItems: Array, nrDays: Int, actualItems: Array, expectedItems: Array) = + "Initial items: \n${describeItems(initialItems)}\n\n"+ + "expected items after $nrDays days:\n"+ + "${describeItems(expectedItems)}\n\n"+ + "actual items after $nrDays days:\n"+ + describeItems(actualItems) + + private fun describeItems(items: Array) = items.joinToString("\n") { " -${it.name}: sellIn:${it.sellIn} quality:${it.quality}" } + + private fun createRandomItem(): Item{ + val nameIndex = random.nextInt(PRODUCTS_LIST.size) + val name = PRODUCTS_LIST[nameIndex] + val sellIn =random.nextInt(MIN_INITIAL_SELLIN, MAX_INITIAL_SELLIN) + val quality = random.nextInt(MAX_INITIAL_QUALITY) + return Item(name,sellIn,quality) + } + + private fun Item.clone() = Item(name,sellIn,quality) + + private fun Array.deepClone() = map { it.clone() } .toTypedArray() + + private fun createRandomItemList(count: Int) = (0..count).map { createRandomItem() }.toTypedArray() + + } - -fun describeTestcase(initialItems: Array, nrDays: Int, actualItems: Array, expectedItems: Array) = - "Initial items: \n${describeItems(initialItems)}\n\n"+ - "expected items after $nrDays days:\n"+ - "${describeItems(expectedItems)}\n\n"+ - "actual items after $nrDays days:\n"+ - describeItems(actualItems) - -fun describeItems(items: Array) = items.map { " -${it.name}: sellIn:${it.sellIn} quality:${it.quality}" }.joinToString("\n") - -private fun createRandomItem(): Item{ - val nameIndex = random.nextInt(productLists.size) - val name = productLists[nameIndex] - val sellIn =random.nextInt(-10, 100) - val quality = random.nextInt(100) - return Item(name,sellIn,quality) -} - -private fun Item.clone() = Item(name,sellIn,quality) - -private fun Array.deepClone() = map { it.clone() } .toTypedArray() - - -private fun createRandomItemList(count: Int) = (0..count).map { createRandomItem() }.toTypedArray()