Software Development

Towards a Theory of Test-Driven Development

This post examines how well we really understand the practice of Test-Driven Development (TDD).

Red, Green, Refactor

By now we all know that Test-Driven Development (TDD) follows a simple cycle consisting of these steps:

  1. Start by writing a test. Since there is no code, it will fail (Red)
  2. Write just enough code to make the test pass (Green)
  3. Clean up the code (Refactor)

The beauty of this division is that we can focus on one thing at a time.Red, Green, Refactor

Specify, Transform, Refactor

Although simple, TDD isn’t easy. To execute the TDD cycle well, we need a deeper understanding that we can only get from experience.

For instance, after doing TDD for a while we may look at the steps as:

  1. Specify new required functionality
  2. Improve the functionality while keeping the design constant
  3. Improve the design while keeping the functionality constant

When we look at the TDD cycle in this light, we see that the Green and Refactor phases are each others opposite.

Refactorings and Transformations

In the Refactor phase, we use Martin Fowler‘s refactorings to clean up the code.


Refactorings are standard alterations of the code that change its internal structure without changing its external behavior. Now, if the Green and Refactor phases are each others opposite, then you might think that there are “opposite refactorings” as well. You would be right. Robert Martin‘s transformations are standard alterations of the code that change its external behavior without changing its internal structure.

Automated Transformations?

Most of us use powerful IDEs to write our code. These IDEs support refactorings, which means that they can do the code alteration for you in a manner that is guaranteed to be safe. So do we need something similar for transformations? I think not. Some transformations are so simple in terms of the changes to code, that it wouldn’t actually save any effort to automate them. I don’t see a lot of room for improving the change from if to while, for instance.

Other transformations simply have an unspecified effect. For example, how would you automate the statement->statements transformation?


The crux is that refactorings keep the external behavior the same, and the tools depend on that to properly implement the refactorings. However, transformations don’t share that property.

Standardized Work

In the Specify/Transform/Refactor view of TDD, we write our programs by alternating between adding tests, applying transformations, and applying refactorings. In other words, if we look at the evolution of our non-test code through a series of diffs, then each diff shows either a transformation or a refactoring. It seems we are getting closer to the Lean principle of Standardized Work. What’s still missing, however, is a deeper insight into the Red/Specify phase.

How to Write Tests

The essential part of the Red/Specify phase is obviously to write a test. But how do we do that? For starters, how do we select the next test to implement?

Unit test failure

There is almost always more than one test to write for a given requirement. And the order in which you introduce tests makes a difference for the implementation. But there is very little advice on how to pick the next test, and this is sorely needed.

Kent Beck has a kata for experimenting with test order, which helps in gaining understanding. But that’s a far cry from a well-developed theory like we have for refactorings. So what do you think? If we understood this phase better, could we come up with the test writing equivalent of transformations and refactorings?

Reference: Towards a Theory of Test-Driven Development from our JCG partner Remon Sinnema at the Secure Software Development blog.

Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Newest Most Voted
Inline Feedbacks
View all comments
10 years ago

I published an article on the advantages of doing TDD here – Get Started on Test-Driven Development!

Back to top button