How to write good unit tests - Part IV: The then part
© Image by Margarethe Pfründer-Sonn↗
In my previous blog post, I’ve written about the setup
and the given
part of a unit test.
This post is about the then
part of the unit test.
These are the most common mistakes in the then
part of a unit test:
bad assertions and good assertions
java’s assert keyword
Java’s↗ assert
keyword only throws AssertionErrors when java was called with the -ae
switch.
If that switch was turned off, then assert
does nothing.
So:
Do not use java’s assert
keyword!
Confusing actual value and expected value
The old JUnit↗ library had an assertEquals
method, where the expected value was the first parameter, and the actual value was the second parameter.
This is the opposite in spoken English or German language.
For me, this has spoiled the assertEquals
method forever.
So:
Do not use JUnit’s assertEquals!
Spock’s equals
Spock↗ has this feature:
In the then:
part, it automatically evaluates every line as an expression.
If the expression evaluates truthy, then the test will pass.
If the expression evaluates falsy, then the test will fail.
So you can write
then:
actualValue == expectedValue
and spock will fail if the actualValue differs from the expectedValue.
but beware of:
then:
actualValue = expectedValue
This is no comparison but a variable assignment. It always evaluates to true, but you can hardly spot the difference!
I once even made an invalid test pass by accidentally comparing two thrown exceptions!
So if you want to use groovy’s↗ assert
or spock’s evaluations in the then
part:
Always, always use strictly TDD’s red-green, red-green style of coding.
Hamcrest matchers
I like reading hamcrest’s↗ assertions, because they are close to the natural English language and provide good error messages.
But writing them is a pain.
AssertJ
AssertJ↗ is my favourite. Reading the assertion statements is nice because they are close to the natural English language, just like Hamcrest. But the best thing: AssertJ has a nice fluent API, so writing assertions is easy: Just use your IDE’s autocomplete features. Additionally, AssertJ has nice assertions for collections.
Too many assertions
Sometimes I’ve seen test method with more than 10 assertions. When reading this, you can not see the forest for the trees. What is the business rule’s intention?
One assertion per test method!?
Maybe you can split the test. You then have two test methods, that share the same given and when part, but the then part is different.
Clean code cheat sheet↗ says:
Only one assertion for one test method.
In my opinion this is sometimes a bit too strict, but the intention is good.
Overspecification
Sometimes some aspects of the business rules we are implementing are not defined by the business experts. Often we developers fill the gaps with good intentions. But sometimes we are on the wrong track. We write unit tests for things, that we think make sense, but in reality this was not defined by the business.
Maybe later we learn that things should be different. Then we want to change the implementation code. But then we will find an existing unit test testing for a different behaviour.
Is that unit test for real or is it just a “developer that filled the gap with good intentions”?
So: If you have the feeling, that you code a test “with good intentions”:
- Add some comments to make this visible.
- Add some comments like: “this bad thing will happen if you remove/change this test” or “when removing/changing this test, please consider/think about…”
Debatable opinion: Maybe it’s better to not write this test!
This blog post was the last one for the setup - given - when - then
pattern.
Next post is the first of a series on writing fast tests.
Any comments or suggestions? Leave an issue or a pull request!