At least ten years ago a clever chap I had the good fortune to work with introduced me to Test Driven Development. He was far less fortunate as at the time I didn’t fully appreciate the benefits of this approach to developing software. After paying some ear service and making minimal effort I lost interest and continued to struggle on the old way. More fool me.
Around 6 or 7 years ago I tried again. I picked up TDD (Beck) put in the effort to get over the hump and never looked back. Now I’m fully hooked; line and sinker. I liken working on a code base without a comprehensive set of unit tests to poking it with a stick until it works. Of course you can never say with a good enough degree of certainty that it ‘works’ without the test suite, you just observe that it does what you are trying to make it do at the time along with everything else you can remember that it should do. When writing even a relatively simple application a developer must consider many factors and eventualities and so I argue that unless you are a genius to rival Einstein or you are writing Hello World you need TDD.
Not only does TDD change the way you write software, it changes the software you write. It forces design decisions to facilitate testing, and this is a very good thing. All modern combustion engines have diagnostic computer systems. The engine has been designed with fault diagnosis as a key design goal. The result is as a user you are warned before the engine suffers a breakdown and you spend less time waiting for it to be repaired when it does. A unit test suite is a diagnostic system. A code base without a comprehensive unit test suite is a liability.
A few years ago I read a job ad. for a ‘Unit Tester’. The job specification made it clear that this role involved taking code written by the development team and writing unit tests for it. Only someone with absolutely no understanding or experience of unit testing could have conceived that position and even less so anyone who actually took the job. The TDD mantra is Test First. It is not Test Last. Writing and satisfying tests is an integral part of the development process, not something done post implementation.
In a nutshell:
- Following TDD enables a developer to focus on what is being built separately from how it is being implemented. Design the interface and the interaction between types before the implementation.
- TDD naturally leads to loosely coupled code. Mocking is an essential part of unit testing, in order to mock effectively classes must be loosely coupled, typically via an interface.
- TDD results in high level of test coverage. Combined with continuous integration this is the best protection from regression bugs and also serves as an invaluable document of exactly how the system is designed to behave.