TDD is the ultimate agile practice. You can’t get faster feedback cycles than with TDD: often a cycle lasts well under a minute. Because of this, you always know that you’re moving to the target.
However, I’ve met very few people who know about TDD, and even fewer who actually practice it. I was at a technical meeting a couple of months ago, where the presenter asked the question who knew about Test driven development. Out of about 50 developers who were present, only about 10 raised their hands. The question who had experience with it managed to raise only three or four hands.
But it’s even worse than that. I’ve worked on quite a few projects, and most of them had a limited set of unittests. The project that I’m working on now only has about 42% coverage, and a good deal of code is covered by useless or unreadable tests. Useless, because the tests don’t actually check the behavior. Unreadable, because of duplications, long setups and multiple asserts per test.
As an industry we know that unittests are important to catch bugs early on. But unittests are often written after the production code, and that’s boring and complicated. So, often it is skipped altogether. Writing unittests before writing production code, or actually, alternating between writing tests and production code, would help.
The main sequence of TDD is as follows:
- Red: Write a test to specify the behavior. This test will fail because the behavior doesn’t exist yet, resulting in a red bar.
- Green: Write the behavior specified by the test. Get it working as soon as possible, it is OK to make a mess.
- Refactor: Eliminate duplications. Both from the production code and from the tests. This last point is important, because the tests need to be readable to be useful.
When you follow this sequence over and over again, you’ll start to notice that the code you produce is quite nice to read, and well factored. The code will tell you how it wants to be designed: design emerges, instead of being imposed on the code.
Fixing bugs is also faster with TDD. Once you’ve located the problem, write a test to verify that problem. Then adjust the test so it will verify the correct behavior. At that point you don’t need to go through the compile/deploy/test cycle again. You just run the unittest to see if you’re making progress. Then, when you fixed the behavior according to the test, you can always test it manually.
The biggest downside of TDD is that it is hard to learn. Perhaps this is the reason why it is not practiced as much as it should. It is a mindset, a habit that needs to be formed. It will take months to get good enough. Therefore, it is recommended to practice on a side-project, or at least practice on small, clearly defined pieces of behavior. But once you do use TDD, you will be a better developer.