Kotlin 79 - I promised
I do some microtests. Didn’t even take an hour, including writing.
I owe us some tests on the current version. If this were a real project, I wouldn’t consider our work to be done unless we had better testing than our current simple characterization test. Well, we can write tests in this version, then perhaps reuse them in the new version. Or copy from them. But … I am excited to begin again.
I shall do the right thing and write the tests. Fortunately for you, the reader, you won’t have to slog through each one. I’ll record enough here so that you can see where they came from, but I won’t take you through all the typing.
OK, I’ve shamed myself into doing the right thing. Let’s get doing.
Testing the Gilded Rose
I’ll begin with a test. The basic idea will be to create an item, update it, and check the results. Let’s start with the easiest one, Sulfuras:
@Test
fun `Sulfuras does not change`(){
val item = Item(PROD_SULF,0,80)
val gr = GildedRose(arrayOf(item))
gr.updateQuality()
assertEquals(0, item.sellIn)
assertEquals(80, item.quality)
}
I had to declare those constants public. Seems fair. I think this is a fair test for Sulfuras, whose sellIn never changes and whose quality is always 80. Test. Green. (And red if I change 80 to 79, so I’m doubly sure that the test works.) Commit: Initial test, sulfuras.
Now, we have to do a lot of tests. I am a lazy person, and I might just copy paste them. But GeePaw did something smarter, and I’d like to try it. He’s quite lazy, is GeePaw, so he wanted all his tests to be just one line, saving wear and tear on his wrist, for which I gather he has other purposes. Let’s see … in our tests …
- The product will vary
- The starting quality will vary
- The ending quality will vary
- The starting sellIn will vary
- The sellIn will always go down by one (except for Sulfuras)
I’d like to do this by machine refactoring, but I see no quick way to do it, and I’m here to get these tests done. I’ll just write it.
fun checkUpdate(prod: String, sellInStart: Int, qualityStart: Int, qualityEnd: Int) {
val item = Item(prod, sellInStart, qualityStart)
val gr = GildedRose(arrayOf(item))
gr.updateQuality()
assertEquals(sellInStart-1, item.sellIn)
assertEquals(qualityEnd, item.quality)
}
I can’t use this for Sulfuras. Let’s do a test for normal products. Is there even one in the text test? Yes, here are a couple of them, values in, values out.
"+5 Dexterity Vest, 10, 20\n" +
"+5 Dexterity Vest, 9, 19\n" +
"Elixir of the Mongoose, 5, 7\n" +
"Elixir of the Mongoose, 4, 6\n" +
I’d like to have constants for those, and create them:
const val PROD_SULF = "Sulfuras, Hand of Ragnaros"
const val PROD_BRIE = "Aged Brie"
const val PROD_PASS = "Backstage passes to a TAFKAL80ETC concert"
const val PROD_ELIX = "Elixir of the Mongoose"
const val PROD_VEST = "+5 Dexterity Vest"
Now I’ll copy one of those test’s results into my new function.
@Test
fun vest() {
checkUpdate(PROD_VEST, 10, 20, 19)
}
Let’s run that and see what we see. We see green. Commit: new test function checkUpdate
used for vest.
Here begins some tedium. I might pop back with special remarks, and I’ll show you all the tests when I have them. My approach is going to be to test against the spec, not against the code. This is quite different from what GeePaw has done in his example, which I hope he’ll publish. His approach to refactoring is that the existing code is to be taken as true, correct, the hand of G*d, absolute and final. It’s shipping and we mustn’t change what ships.
I completely agree with that. And since I have a spec, I propose to test against it, and to see whether, by change, there might be bugs in the existing code. If there are, I won’t fix them, but I will ask the owner, Allison, about the discrepancy.
Anyway, you have a nice rest while I beaver away here.
- Done!!
- That took well under an hour!
OK, that wasn’t so bad, and I didn’t find anything that seems like a bug. I kind of like those one line tests. Commit: Tests for all cases, I’m pretty sure …
If there’s a lesson for me, it’s that once you get into it, testing can go pretty smoothly. It also inspires me to come up with an easier way to test in the ADVENTure program, which I’ll get back to shortly.
Here are the tests. See you soon!
@Test
fun `Sulfuras does not change`(){
val item = Item(PROD_SULF,0,80)
val gr = GildedRose(arrayOf(item))
gr.updateQuality()
assertEquals(0, item.sellIn)
assertEquals(80, item.quality)
}
@Test
fun `normal product degrades by one before sellIn`() {
checkUpdate(PROD_VEST, 10, 20, 19)
}
@Test
fun `normal degrades 1 point on last day`() {
checkUpdate(PROD_ELIX, 1, 10, 9)
}
@Test
fun `normal degrades 2 points after sellIn`() {
checkUpdate(PROD_ELIX, 0, 10, 8)
}
@Test
fun `brie increases always`() {
checkUpdate(PROD_BRIE, 20, 5, 6)
}
@Test
fun `passes increase by one before 10 days`() {
checkUpdate(PROD_PASS, 20, 20, 21)
}
@Test
fun `passes scenario`() {
checkUpdate(PROD_PASS, 11, 20, 21)
checkUpdate(PROD_PASS, 10, 20, 22)
checkUpdate(PROD_PASS, 5, 20, 23)
checkUpdate(PROD_PASS, 1, 20, 0)
}