Nobody likes to fail. Such a simple word implies so many negative connotations: Laziness, incompetence, unprofessionalism, and more. With that in mind, it’s interesting to consider the fact that Unit Tests are all about failure!
Fail Early, Fail Hard
You might be scratching your head at this point, wondering what I mean by that. Aren’t unit tests supposed to pass? As usual, the answer is a bit deeper than the surface. Much like the canaries that miners used to carry with them to detect noxious gases, unit tests serve as an early indicator that something is wrong. In a traditional TDD workflow, failing tests are a normal occurrence (in fact, with strict TDD, you start with a failing test). The test runner makes failures clearly visible after each test run. This is a good thing because it reduces the likelihood of overlooking a failing test case.
In fact, unit testing’s primary value comes from failing tests, detecting bugs as early as possible in the development cycle. Multiple studies have shown that the cost of fixing software bugs rises dramatically the later the defect is discovered. To illustrate, let’s look at a hypothetical example, imagining a team working on a commercial software product when a bug is introduced: