I am writing a little off-the-clock code for a dasBlog macro to manage books that
I read. I decided to use TDD for this project, using VS2005 and the MS unit
testing framework. Much needless heartburn has been had debating the nature
of TDD and how it is exactly performed. The primary debate has been whether
tests must be written before the code they are going to test.
The way I like to think about this is whether or not a developer will have intellisense
in his test fixture. If a test fixture is being written for a class that does
not yet exist, then the IDE will not have intellisense for the nonexistent class.
If the class to be tested does exist, then intellisense will function against that
class.
Even if the shell of the business class exists, it need not be implemented.
For instance, if I am implementing my Book class and I know that it will have
Title and ISBN properties, may the Book class and its properties exist before
I create the test fixture for it? It turns out that in Visual Studio 2005, the
test class can be generated for me against my classes shell. This is great stuff.
The macro extension model for dasBlog calls for me to write a System.Web.UI.Control
that gets instantiated and served up by the dasBlog runtime. I have access
to anything that a Web.Control has and therefore I did something dumb. As I
began implementing my control, I referenced the current HttpContext. This is
a bad practice, but so darned easy to do when you are a hurry.
I spent a few minutes implementing my Control, and then flipped over to the test
class. Admittedly, I had already coded a bit of my implementation including the
HttpContext code. I generated my test fixture class with the IDE and invoked
my business class from the fixture. I ran the test and it blew up when the Control
tried accessing HttpContext. Duh.
Here is how I caught myself doing something stupid using TDD.
- I created my business class in my main project, in this case a Web.Control.
- I added a property to it. I did not implement the get; set;
- I overrode Init(). I put some code in there. That code called HttpContext
- I generated my test class with the IDE in a separate assembly and hydrated the control.
- It blew up
- I removed the reference to HttpContext and replaced it with an argument to the constructor.
- I changed my test method.
This is the exact definition of refactoring, and it only took 5 minutes to catch myself
doing it the wrong way using this version of TDD.
I don’t care if this was “official” TDD or not. As long as the code and tests
don’t get 10-15 minutes out of phase with each other, you keep your risk low.
Can I implement a business class before I implement the test class for it? Sure.
Should I code the whole thing before adding the test? No.
As with all things, drinking TDD in moderation works best.