Three levels of TDD


I’ve been using TDD technique for a few years. Most of the time with satisfactory a result. But it wasn’t an easy journey; it was a trip full of ups and downs. During this period my thinking about TDD has changed dramatically, or maybe I have changed my perception of testing and software development during this time? Indeed, yes I have.

Lasse Koskela in his book called “Test Driven: TDD and Acceptance TDD for Java Developers.” wrote that “TDD is a technique that evolves together with the practitioner.” In this blog post, I would like to describe my own evolution in this matter.

Red Green Refactor Circle

Level 1 - Fundamentals

You begin your journey with TDD. When you are new into something, you want to follow the rules strictly. One is TDD circle, which is “RED, GREEN, REFACTOR”. You have also heard about three laws of TDD defined by Uncle Bob:

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

You are very confused about TDD because all examples that you can find relate to some mathematical/algorithmic problems. But in your daily job, you are obligated to write features, talk to DB and the other systems. You probably are struggling with complex dependencies, maybe you have to use mocks.

But finally, after some practice you start to see the benefits, which are:

  • You’ve noticed short feedback loop. Immediately, when you complete your implementation, you can launch the test to verify the correctness of your code.
  • Test code coverage gets higher. No matter how you measure it, it will be higher.
  • Regression is not a problem. Because when you break previous functionality during refactoring, you will instantly know that.

Level 2 - Requirements

Task lists

Task lists work perfectly for me. When I implement a business requirement, each small step or each corner case is represented by one task in my task list.

Then for each task I write one test, often I use parametrized tests to extend tests quickly. Finally, after a few TDD circles, my task is finally completed, and I can move on.

But sometimes during my work new system requirements appear. Often because the domain is so complicated that it’s hard to predict all the functionality up front. There is a big temptation to do it now, during the work on the current task, but it is dangerous. By doing it, you can lose your focus on your current goal.

I’ve practiced the habit which consists of adding this new requirement as a new task to my task list and complete it after the current one. Then you gain some time to think about this need, to decide if it is an essential functionality to do.


At some day, you will discover Behaviour Driven Development. For example, look at this specification:

Scenario: Customer has a broker policy so DOB is requested
Given I have a "Broker" policy
When I submit my policy number
Then I should be asked for my date of birth

It is a very well written test scenario. Moreover, it is an executable scenario. This text can be executed with the tool called Cucumber. You don’t have to use it. You can use standard test framework and write your test using fluent test libraries or you can build your fluent API for tests if needed.

Start writing tests that will not only check your code but also be valuable documentation for your system.

Level 3 - Understanding

Show me your tests and I will tell you everything about your code.

TDD sometimes can also mean “Test Driven Design”. When you start thinking about it, your main reason for writing the tests is to refactor and re-engineer your codebase freely. For me, it is the highest value which you can get from TDD. How to achieve it? Try not to “cement” your code. Try to test interfaces or facades but not bolts and nuts of the implementation.

How to check if your tests are correct? Remove production code and try to rebuild it in a different way basing only on tests.


In this article, I presented fundamental rules of TDD. The topic of requirements were also discussed. In the end, I told you about Test Driven Design which for me is a valuable part of this technique. I hope that your understanding of TDD will improve and you will start writing better tests and better systems.

I gave a speech about TDD. Slides available at

Photo credits: Banner, Thumbnail