Use ShouldKO for better assertion messages

junit, hamcreset, kotlin, assertion, tests 2 mins edit

Most of us write tests these days. Whether they are unit, integration, end-to-end or performance tests once written we often do not go back to them until they fail. It is thus vital to have a clear assertion message when a test fails.

search

Hamcrest

I think Hamcrest is the most popular assertion library available in Java and Kotlin ecosystem. Let us look at an oversimplified example of Money class:

import java.math.BigDecimal
import java.util.*

data class Money(val amount: BigDecimal, val currency: Currency) {
    operator fun plus(other: Money): Money {
        if (currency != other.currency) {
            throw IllegalArgumentException("Cannot add $this to $other. Currencies must match.")
        }

        // an accidentally introduced bug 😈
        val newAmount = amount + other.amount + 10.0.toBigDecimal()
        return copy(amount = newAmount)
    }
}

Imagine we write a test for the plus operator using JUnit and Hamcrest:

class MoneyTests {
    val usd = Currency.getInstance("USD")

    @Test
    fun can_add() {
        val usd100 = Money(100.toBigDecimal(), usd)
        val usd50 = Money(50.toBigDecimal(), usd)

        assertThat((usd100 + usd50).amount, equalTo(150.toBigDecimal()))
    }
}

The test will fail with the following message:

java.lang.AssertionError: 
Expected: <150>
     but: was <160>

Let’s see how we can improve on that.

ShouldKO: better assertion messages for Kotlin

ShouldKO is a simple library I’ve come up with that improves the assertion messages. Its idea is based on assertion libraries available in .NET e.g. Shouldly. Let us see how the tests looks like using ShouldKO:

class MoneyTests {
    val usd = Currency.getInstance("USD")

    @Test
    fun can_add() {
        val usd100 = Money(100.toBigDecimal(), usd)
        val usd50 = Money(50.toBigDecimal(), usd)

        (usd100 + usd50).amount.shouldEqual(150.toBigDecimal())
    }
}

In my opinion ShouldKO’s assertion syntax improves readability. However, this is not where ShouldKO main improvement is. Follow the improved assertion message:

java.lang.AssertionError: (usd100 + usd50).amount 
Expected: <150>
     but: was <160>

ShouldKO incorporates a source code line with the assertion into the assertion message itself. This comes really handy when we have multiple lines with assertions that form one logical condition. This is a small thing, but can greatly improve debugging test issues especially when all we have is a log file produced by a test run.

Installation of ShouldKO

ShouldKO is currently available on Jitpack. You need to first add Jitpack to your repositories:

repositories {
    maven { url 'https://jitpack.io' }
    mavenCentral()
}

And include the library in your tests e.g.:

testImplementation 'com.github.miensol.shouldko:hamcrest:v0.1.0'

ShouldKO’s Hamcrest library allows for using any Hamcrest matcher.