Posted by johnsmart
on June 2, 2008 at 3:44 PM PDT
Let's not be pedantic. Write unit tests before you code a method, or after it - in my experience, it matters little, as long as you think about and write the tests at roughly the same time as you write the code. It's coming back to do the tests later (or not coming back at all) which causes problems. Personally, I like to write unit tests just before or immediately after writing small chunks of code - it doesn't break the flow, because it is part of the flow.
This takes a little practice - inexperienced developers often have trouble knowing what tests to write. But this may reflect the fact that they are unsure as to what code to write as well. Some people have commented that TDD can encourage micro-design - very low-level design without taking into account the bigger picture. This can happen with inexperienced developers, or if you apply the approach too pedantically. This is where approaches like behaviour-driven development are cool. Do you write a unit test for a getter method before you write the getter method? Then maybe your unit tests should be a little more high-level, and closer to the user (or system) requirements.
But getting back to the fundamentals, why do I like unit tests in the first place? Simple! My practical experience tells me that they help improve code quality, and save time debugging. The upfront time taken to write ten small unit tests is much less than the time taken to fix bugs later on that would never have happened if the code had been unit-tested correctly.
Indeed, I frequently see coding problems that would never have occured had the code been properly unit tested. A recent example: over an hour hunting down a problem in a web application, in what appeared to be correctly-written Spring-MVC code. It turned out that a validator class was swallowing an exception. We found this problem easily, immediately in fact, upon seeing the code (code reviews are effective, too). But, the point is, we spent an hour or more finding the right class to review. And this problem would have been detected, and fixed, very quickly if the code had been properly tested.
In my experience, when people set out to write unit tests after the fact, they write them poorly, as an afterthought ("I've finished all the code, now I just have to write the unit tests"). Or not at all. In this case, is the code really finished? Well, if it works perfectly, it is, in which case, writing the unit tests looses a good chunk of its value proposition. But often it doesn't, and the unit tests written afterwards will be superficial, and will not always test the code well. Or, developers run out of time and don't bother with testing at all.
TDD is like any other coding practice. When you are learning any new technique, you tend to follow the instructions to the letter. Similarly, when you learn a martial art, you try to duplicate the master's movements to the letter, without necessarily understanding the underlying logic. Once you are familiar with a technique, having experienced and worked with it, you understand it better. Then you can improvise, and mix the new technique with other ones that you have previously mastered.