TDD Basics

Last Updated: 18th June 2019

This post is based on a recent talk and live demonstration that I gave at work. The audience consisted of software developers and data scientists. The aim of the talk was to introduce and clarify the concept of test driven development and to encourage adoption. The slides can be downloaded here.

Introduction

The Wikipedia defines Test-driven development (TDD) as follows:

“Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, then the software is improved to pass the new tests, only.”

- Wikipedia

This definition describes a process. This process consists of short cycles between writing test cases and writing production code that make the tests pass.

Kent Beck, the “rediscoverer” of Test-Driven Development has been quoted to say:

“TDD encourages simple designs and inspires confidence.”

- Kent Beck

Confidence is a very important word in this quote and I believe is what makes TDD so valuable. When all unittests pass after the implementation of an enhancement or bug fix, you can be confident that the critical functionality is still operational.

Simple designs and confidence also lead to less time spent debugging as code is easier to understand and bugs are therefore easier to find and fix.

Robert C. Martin also known as Uncle Bob:

“Nothing makes a system more flexible than a comprehensive suite of tests! Far above good architecture and good design!

This can’t be overstated. If you want your systems to be flexible, write tests. If you want your systems to be reusable, write tests. If you want your systems to be maintainable, write tests.”

- Robert C. Martin

Here Robert is clearly a massive advocate for TDD. I think that what he means is that if you have a full suite of tests that cover a sufficient amount of your production code, then you can refactor to any architecture and design you like. You will always have the confidence that everything still works after the refactor, as long as all of the unit tests still pass.

The Three Laws of TDD

To define TDD, the three laws were declared by Robert C. Martin. These consist of idealised rules, which when followed, make up the process of TDD:

  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.

The first law describes that a failing unit test must be present before any production code has been written. This sounds counterintuitive as we instinctively want to go for the production code first. Also how can we test what doesn’t exist?

The second law explains that only enough of a unit tests must be implemented that is sufficient to fail. That means that if your unit test fails after the first line, then you need to stop and move over to writing the production code to make that bit pass. This is challenging to do at first as it may seem that you may never get any work done this way.

The third law is similar to the second but states that you must stop writing production code as soon as the failing unit test passes. Then you will need to go back to writing more of your unit test until that fails again. The cycle goes on until the feature is fully implemented.

It looks like we are just going to have to trust the process and see for ourselves.

The Red-Green-Refactor Pattern

The Red-Green-Refactor pattern is an easy to use and memorable framework in order to implement the laws of TDD from the previous section. The cycles of TDD according to the Red-Green-Refactor pattern consist of the following three steps:

  1. Red: Implement just enough of the unit test that is sufficient to fail.

  2. Green: Implementation of just enough production code to make the unit test pass.

  3. Blue: Refactor if necessary.

The third step wasn’t mentioned in the laws. However, it is important to consistently clean up your code as you go along. Common refactoring tasks such as removing duplication, function/class extraction, and variable/function renaming will make the code much more readable and easy to maintain. The process of refactoring may also reveal a path to a more elegant solution.

Kata

Kata is a powerful learning technique which we can adopt in programming.

The word Kata comes from Japanese martial arts, which are patterns of choreographed movements. They are practiced as a way to internalise those movements and techniques. The aim is for the practitioner to be able to execute and adapt those patterns under any circumstance.

We can do the same with programming where the muscle memory gained by repeatedly typing out non-trivial solutions will lead those patterns to become second nature. This reduces cognitive load which helps solve even more complex problems in less time.

In the live demonstration I chose to perform the well known “Prime Factors Kata” using the Red-Green-Refactor pattern of the previous section. This is a very simple kata to perform that demonstrates the ideals of TDD clearly. I also like it a lot because an algorithm emerges out of the many small incremental changes with no up-front design. This reveals TDD as another perspective for looking at programming problems, and is therefore a valuable tool to have at our disposal.

I have included the steps of the demonstration at the end of the talk slides, and I recommend that you follow along to get a deeper appreciation of what has been discussed in this article.