Effective Testing - Expressive Assertions
Using expressive assertions can help us figure out why a test fails without having to go through the code.
Let’s start with an example. Here’s a test making sure our recipe has tomatoes đ
At first glance, everything looks ok. The test passes, it is easy to read, and it follows the âGiven - When - Thenâ structure.
Some months go by, and one day our test starts failing.
At this point, we’ve probably forgotten everything about the recipe, and weâre not sure whatâs causing the failure. The test name is not helping us much either.
To avoid this situation, we can include a message that will be displayed whenever the assertion fails.
Now the failure is obvious. There is no đ on the recipe. We can immediately tell whatâs wrong without even looking at the test code. But we can do betterâŚ
Assertion libraries
Let’s face it, writing this kind of detailed message for every assertion would be a pain in the ass. Fortunately, we donât have to. Instead, we can use an expressive assertion library to do the heavy lifting for us. This is how our code would look like using Strikt:
We’re using Kotlin infix notation to make the code more readable. This a stylistic decision, you donât have to use it if you donât like it.
You might notice we’re calling the contains
method on the assertion itself. This is possible because Strikt can tell that the type weâre asserting on, is a String, and thus, it can provide methods explicitly tailored to Strings. This is what the error message would look like in this case:
Almost the same information we got from writing our own message, but without the boilerplate.
Assertion libraries are like swiss army knives; they provide all kinds of assertions for different types of objects. I suggest learning a few of the core ones through the documentation, and then letting the IDE guide you with auto-suggestions to discover new ones.
Here are some more examples of type-specific assertions:
Asserting on objects
When validating properties on objects, you might be tempted to write something like this:
You can probably tell why this is bad. By the time we see the failure, we no longer have context on what property weâre asserting.
Was it checking the title
, the author
, or something else?
Instead, you can take advantage of the fact that Data Classes automatically get equals
and toString
implementations. So we can use an assertEquals
and get a nice looking message showing us both instances.
If we don’t care about comparing all properties we can use Strikt to assert only specific fields:
The block assertion style means that even though the title assertion failed Strikt will still check for page count and itâll provide output for all the assertions in the block.
This post is part of the Effective Testing Series.