Occasionally someone asks me the question whether it’s necessary to test the code of solitary tests? Usually this question is ushered by folks who are opposed to the idea of automated tests. Somehow they have the notionthat one can keep writing tests for tests for tests for tests, etc. Obviously this is a complex and absurd thing to do. This attitude often stems from test code being overly complex to the point that an average developer is no longer able to understand the scenario at hand.
Solitary tests should be simple and easy to read because we need to be able to easily verify their correctness. This is also where the age-old principle of double-entry bookkeeping comes in.
According to Wikipedia, double-entry bookkeeping:
Is a system so named because every entry to an account requires a corresponding and opposite entry to a different account. The double entry has two equal and corresponding sides known as debit and credit. The left-hand side is debit and right-hand side is credit.
Applying this principle to automated tests means that the test code verifies the production code, and that the production code verifies the test code. This means that solitary tests can be tested by introducing the very bugs in the production code that they are intended to verify and detect. The easiest and fastest way to accomplish this is by first writing a failing test before writing the implementation that fixes the test failure.
When we add solitary tests after writing the production code, then it’s more difficult to determine whether these tests are making the proper observations. The only way to determine this is to temporarily remove or comment the production code again to see if the test fails or not. This approach adds more overhead to the development process with an extra back-and-forth between the production code and the test code compared to a test-first approach. Regardless of whether we use Test-Driven Development or not, we should always see our solitary tests fail. This makes them more trustworthy. Never ever trust a test unless you have seen it fail!
Even when rigorously following the principles of Test-Driven Development the test code is only verified once, right after it has actually been written. What will happen when we change any of the code later on? In order to avoid going down the rabbit hole of writing tests for tests for tests, we need to be able to visually verify the correctness of our solitary tests, by using our eyes and our brains. And in order to easily do this, test code should be simple, small, discoverable and easy to read.
How can we accomplish this? For starters, test code should always have a cyclomatic complexity of 1. This is a software metric used as a quantity measure for the number of linearly independent paths through a program’s source code. It’s a very useful indicator as it indicates the number of pathways through a (test) method. This directly translates in never, ever using any branch constructs in the code of a solitary test like “if” statements or “for” loops.
It’s also quite important to avoid testing too much functionality in a single test. We should therefore try to focus on a single concern at a time. That is why designing production code for testability is such an important consideration.