The unit tests you produce in TDD represent an investment. You’ll want to ensure they continue to return on value and not turn into a liability.
As a first step, find the right frame of mind. Start by thinking about your unit tests as part of your production system, not as an adjunct effort or afterthought. We consider the diagnostic devices built into complex machines (e.g. automobiles) as part of the product. Software is a complex machine. Your tests provide diagnostics on the health of your software product.
Here are some common concerns about TDD:
- The tests will have their own defects.
- I’ll have twice as much code to maintain.
- The tests are handcuffs.
- Testing everything (via TDD) results in diminishing returns.
I’ll tackle each one of these in a separate post, offering some thoughts about how to reduce your anxiety level. (No doubt I’ll add other concerns along the way.) Then I’ll move on to how to craft tests that are more sustainable and anxiety-free.
The tests will have their own defects.
It is absolutely possible for a unit test to be defective. Sometimes it’s not verifying what you think it is, sometimes you’re not executing the code you think you are, sometimes there’s not even an assert, and sometimes things aren’t in the expected state to start with.
Strictly adhering to the TDD cycle (red-green-refactor) almost always eliminates this as a real-world problem. You must always see the completed test fail at least once, and for the right reason (pay attention to the failure messages!), before making it pass. And writing just enough code to make it pass should help reinforce that it was *that code* that passed the test.
Other ways to ensure your tests start and stay honest:
- Pair or mob (or review the tests carefully with some other form of review).
- Minimize use of complex test doubles, such as fakes.
- Avoid partial mocks at all costs.
- Don’t mock past immediate collaborators.
- Employ contract tests.
- Fix the design issues that demand complex test setup.
- Stick to single-behavior tests.
- Design tests for clarity. Emphasize test abstraction and employ AAA.
- Always read the tests carefully as your point of entry to understanding.
- Improve each test, as warranted, each time you touch it.
Next: The tests are handcuffs.