Adventures with Test Driven Development
I’ve recently had a chance to use Test Driven Development (TDD) while developing a new piece of software; this is something I’ve been wanting to do for a while but was waiting for the chance to try it out with a completely new project. The work involved wrapping a C library with a C++ wrapper and then wrapping that C++ wrapper with a managed C++ wrapper so I could then use the library in a C# application. I originally planned to use only one C++ wrapper but I couldn’t figure out a way to deal with abstract C structures in managed code so I ended up creating the C++ wrapper to isolate the managed code from those abstract structures.
For those that have not heard of TDD, or can’t remember what it involves, it is essentially a methodology that encourages the use of unit tests and quick iterations to develop software that matches the functionality specified in the unit test. TDD can be thought of as a five stage loop where one complete rotation is one iteration of the software, the five stages are:
- Write a new unit test.
- Run all the unit tests and see if the new test fails.
- Write the minimum amount of code to make the test pass.
- Run the unit tests and see the test pass.
- Refactor were necessary to remove duplication.
This sounds simple and it really is; the core of the idea is that the test in step one is effectively specifying some new functionality, which we then test and if the test fails, implement in the simplest manner possible in step three. This is followed by making sure all the new tests plus older tests still succeed in step four, and then in step five we refactor the program as required to remove duplication.
I’ve always like the idea of unit testing software as it seemed to me it would make regressing testing very easy and gives the developers more confidence in the quality of their software, as well as making refactoring a lot easier as the unit tests provide a simple and easy way to test to see if the refactoring caused any unexpected breakages. All these benefits observed during my trial use of TDD, plus one unexpected benefit, made me think a lot more about my program composition and my interfaces. This proved an unexpected bonus and was mostly born from a desire to make it easier to test my classes and methods.
One of the most common arguments I heard against unit testing is that it costs more time than it would to not write the tests; this is simply not true as this chart highlights. Writing tests for TDD may take longer to do than implementing the same solution without tests but the cost of fixing the bugs are moved forward in time with TDD which makes them a lot cheaper to fix, as the closer in time the detection and correction of a bug the quicker (and hence cheaper) the fix. So the assertion that unit tests mean ‘X% less features’ is simply wrong; unit tests mean more features as they make bugs cheaper to fix. This does not mean TDD and unit testing is not without flaws. I’ve yet to hear of an easy or simple way to unit test Graphical User Interfaces (GUI) as well as we can currently test source code.
In summary I’d recommend you give TDD a try if you haven’t already and if you’re using a .Net language I’d recommend NUnit as your unit testing framework.