One objection to the practice of TDD I’ve heard from several different people is along the lines of “I don’t know exactly what I’m building at the outset, the code is experimental, so how can I write tests for it?”
Frequently it is the case that you have an idea but don’t know the mechanics of how you’re going to implement it. I find this particularly when I’m writing code that extends a third-party library. You don’t know exactly where the API hooks you’ll need to use are, your understanding of the API is fuzzy and you expect to learn it as you go. So how do you test-drive in that situation?
XP has a recommendation here: write a spike then throw the code away once you have enough understanding of the technical solution to approach the problem in a more rigorous manner. In my experience that practice, while valid, doesn’t sell TDD to a doubter.
What I think really causes the original objection is that the person in question is thinking at the wrong level. They’re mentally diving straight in to code, to the solution, to the elegant and shining temple of technical brilliance they’re about to erect. They’re thinking about how not what.
Step back. Sure, you don’t know what your code is going to look like or how it’s going to interface with anything. If you try to start with low-level unit tests now you will spend a lot of time re-writing tests for fine-grained interactions when you need to take a different approach.
Two things you do know are what is going in to this thing you’re going to build and what you want to come out of the other side. So test that. Test that at a high level.
isLoggedInAs(username)), elide over the irrelevant detail (we might require some other information when a user registers but we can add that later).
None of those things require you to know how the code you’re going to write is going to work. They require you to think about and formally specify what you expect in the way of input and output. It forces you to define the coarse-grained behavior of the software you’re designing – what you want it to do. The how now has a framework for success into which it can grow.
In Growing Object-Oriented Software Guided By Tests Steve Freeman and Nat Pryce describe this style of testing as outside-in. You start with high level tests using a “walking skeleton” and progressively work inward adding more detail and drilling down to low-level unit tests and the accompanying fine-grained behavior. The walking skeleton is fleshed out as you go and by the end of the process has evolved into a passing end-to-end acceptance test suite.