A friend recently criticized the way that I write unit tests.
According to him, we should only test one expectation at a time; so, we can only have one assertion per test.
Now, I completely agree with the “test only one expectation at at time” philosophy. However, I completely deny that that implies we should only have one assertion per test.
Unfortunately, I’ve noticed that a large portion of developers buy into this mantra; and under some circumstances, it actually has very good results. However, it also has the potential to block developers from writing clear and meaningful tests.
Confusing Strategy for Tactics
For this discussion, I will use the arrange-act-assert paradigm of software testing.
In order to test the “uniq” function, I could use the following jasmine code
Superficially, this test seems to follow the “one expectation; one assertion” rule. However, consider what it means for the test to fail.
What postconditions could make this a failing unit test? From the top of my head, I can think of the following scenarios
- The result is not an array
- The array has more or less than 4 elements in the list
- Index zero of the array is not 0
- Index one of the array is not 1
- Index two of the array is not 2
- Index three of the array is not 3
This implies that the following unit test is at least as powerful.
Tasting the Forbidden Fruit
Even though the first unit test had only one assertion, it actually checked at least 6 different postconditions.
This proves that the “one expectation; one assertion” rule does not work (in general); so, feel free to use as many assertions that you want and need.
Personally, I find that aiming for “one expectation; one assertion” makes me write cleaner tests. However, I’ve also found situations where it makes me write complex or cumbersome tests. My milage using “one expectation; one assertion” varies depending on the type of test.
I would recommend everyone at least try to aim for the ideal of “one expectation; one assertion”, but only as far as it helps you write good tests. At that point, you should throw it away.