Image via Wikipedia
I really like this article from James Grenning that talks about the time and effort savings in debugging when you write your unit tests first. In it, he demonstrates that what we commonly think of as “debugging” a piece of code is typically a chunk of effort that is fairly significant with each piece of code that we write, so he compares the cost of this effort as part of the development process as opposed to coding, “finishing,” then debugging as part of testing.
I totally agree with all that.
The problem is that this makes the primary value of unit testing “time saved while debugging” and, in the article, is generally contrasted with having no tests at all. Some of the commenters chimed in with, “What about writing tests before you check in?” James maintained (rightly so) that writing tests first is still a savings, but we’re clearly on shakier ground, now. If the value of TDD is finding bugs early, is there much of a difference between writing tests first or writing them last? I would say the difference is relatively small either way.
The primary value in writing tests first is that you’re designing your code. You write the tests around what you expect the code to do in order to complete its job. This is defined, ultimately, by the functionality you’re trying to create (i.e. features).
Then, you write the code to satisfy those tests.
By doing this, you aren’t just going to catch bugs in an automated fashion, you’re:
- Making sure you only write the code that you need to support the requested functionality.
- Making sure that your code actually does what the functionality requires rather than simply working bug free.
Unit tests should be prescriptive, not descriptive. In other words, unit tests should define what your code is supposed to do, not illustrate after the fact what your code does.
In archery, you set up a target, first, then you shoot at it. You define success, then try to implement that success based on the definition. You don’t shoot an arrow, then paint a target around it. In other words, you don’t define success by what you did, you do the right things based on how you’ve defined success.
If we want to talk about time savings, the sheer amount of savings in the code that you don’t write is usually much more than enough to justify taking time to write the tests, and that’s not even adding the debugging time savings in that James talks about.
If you write unit tests (or worse, generate them – MSTest, I’m looking at you) after you write your code, you are missing out on what I believe is the most significant benefit to TDD.