On discovering Test-Driven Development
Posted on Sat 01 October 2011 in Coding
Test-Driven Development (TDD) is a programming practice that to me is an immensely useful quality assurance tool. In brief, TDD is about writing unit tests first and letting the unit tests drive the design of your code. Some of the most important benefits are:
- The public API your create becomes usable and testable.
- Test coverage becomes very high, because you wouldn’t add any code without writing a test for it first.
- You catch nasty surprises early (read on for an example).
- You build a safety net that allows you to refactor your code later on, knowing that you won’t introduce bugs.
Surprisingly, many people don’t use TDD, presumably because they don’t know about the benefits (because if they did, why would they NOT use TDD?). The most common argument against using TDD that I have encountered is “but I don’t know which tests to write, I need to experiment a bit with the code first.” My response is usually that with TDD, they can experiment all they want with the added benefit that they know when they are finished (when the unit tests are all green) or when the experimentation has taken them off course (when the unit tests are NOT all green).
Recently, I had a discussion with a customer about TDD. The person told me that there had been no company-wide directive to use TDD, so they didn’t. (But here had been one project in which they sort of “piloted” TDD, and it didn’t work out so well.) For some reason, this resonated so badly with me, and I soon figured out why. I have always considered TDD to be a personal tool that I as a programmer can use to be a better programmer, to write better code. And to be adept with any tool, you need to familiarize yourself with the tool and practice using it. You cannot just be told to use it. But you can be encouraged to!
So if you don’t already use TDD, I encourage you to do so! It will be a difficult journey with many obstacles, because TDD is really, really hard to master. Heck, writing a unit test regardless of methodology is hard enough already. But in the end, when you have added TDD to your tool belt, you will find it to be very powerful! And at this point, using TDD will be part of your job as a programmer. Put in other words, TDD will be something you use for you own sake, and nobody else can control whether or not you use it.
I will end with a short story: A few days ago, I wrote unit tests for a
pretty simple value object class with three properties. The class
naturally implemented GetHashCode
and Equals
(it was a .NET class).
Would you write unit tests for those methods? If you did, would you
test-drive them even? Perhaps to some people, these are methods that are
so much infrastructure that writing tests for them is a waste of time,
especially since they can be automatically generated. But I test-drove
them, being the TDD addict that I am. And it totally saved my day! You
see, in Java I would let Eclipse generate the hashCode
method, and the
pattern it generates is to start with a small hash value and for each
property multiply the hash code of the property with a prime and add to
the hash value. I implemented the same approach in my value object
class, ran the unit tests and watched them go red! What happened? My
GetHashCode
implementation threw an OverflowException
exception
because of integer addition overflow.
(I then went on to learn that this problem is well-known in the .NET
world, and there are various ways around it. For C#, there’s
unchecked
, but this was VB. In Java, integer addition overflow is not
a problem, because as stated in the Java Language Specification, section
15.8.2: “If an integer addition overflows, then the result is the
low-order bits of the mathematical sum as represented in some
sufficiently large two’s-complement format.”)
So because of my unit tests, I became a better .NET programmer. Thanks TDD!