TDD does not mean writing all the tests up-front

written on 2022-05-04

There is a common misconception regarding TDD (Test-driven Development) which I frequently encounter in discussions or interviews, when I ask: "Do you actually practice TDD?" Often the answer will be something like "No, I cover my code with tests later. It is unrealistic to write all the tests first, who even does that?"

And they are right. Of course it is completely unrealistic to write all the tests first, like this:

Illustration with one block of test-writing and one block of implementation

It would require you to have a complete mental model of all the units of code you are going to write, all interfaces, classes, functions. And that goes against the core agile idea of working iteratively, step by step.

But this is an incorrect understanding of TDD. "Driven" by tests does not mean having all tests done first. It just means that tests are driving you alongside with the implementation.

Robert C. Martin says it best in The Three Laws of TDD:

Over the years I have come to describe Test Driven Development in terms of three simple rules. They are:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

So this means that you keep switching between tests and implementation constantly, looking more like this:

Implementation with alternating test writing blocks and implementation blocks

Yes, you write the test case just slightly in advance of the implementation, but only a tiny piece of it. This way, you are clearly not required to have a full mental model of your code design. You can explore your API step by step, truly "driven" by the test cases. If you need an example of how this can work, read Engineer Notebook: An Extreme Programming Episode.