February 7, 2012

BigVisible Blog

What is Test-Driven Development?

This question has been at the forefront of several conversation I have had lately both with highly experienced Agile coaches and with new, interested parties at the client. The question has been answered many times from many different points of view, and most of us who have been around Agile for a while think we know what it is. There are a few misconceptions out there, though, and I want to clear the air. So, what is TDD, really?

Test-Driven Development is a disciplined approach to software design that provides a mechanism for programmers to create working software in tiny increments of no more than a few lines at a time. The reason that this is important is that Agile approaches to software development more or less require us to deliver working software in small increments that fit inside a two-week iteration (give or take.) In order to have working software that meets some customer need in such a short time frame we need a way to create even smaller increments of software, see them work, build a little more, see that work, etc., and improve the design as we go so that we don’t create a mess.

The way that Test-Driven Development accomplishes this is by leaning on unit testing frameworks to build a tiny test that specifies a tiny increment of behavior. We write that test before we have written the production code that will make that test pass. Then we write the code, taking care to do no more than is absolutely necessary to make our test pass. Finally, we take a step back and look for indications that our design could be improved, the main one being duplication that is created by bits of code that do or say much the same thing. When we see such duplication we refactor it using techniques and tools that allow us to change the code safely without breaking the test.

TDD Cycle

We repeat this process over and over. Each cycle takes no more than a minute or two, and each cycle builds incrementally on top of the prior ones until we have created some working feature that the customer has asked for. All the while we are seeing all of the small increments we have built work, via the tests. All the while we are seeking and exploiting small opportunities to improve and simplify the design of the code. And, in the end we have demonstrable, working software that is capable of filling some customer need. All we have to do is integrate and deploy it and we can safely move on to the next thing on our list.

That is more or less it. So, now that we have talked about what Test-Driven Development is, let’s take a moment to discuss what it is not:

Test-Driven Development is not about testing, not really. The purpose of tests is to verify the quality and functionality of software. The purpose of what we are doing is to set an expectation of what we need to do next and have a way to quantify when that expectation has been met. We get verification as a result. That is: later we can run the tests and see them pass and be assured that no regression has happened (At least in the behavior that we specified.) But, that is not the goal that we set out with. We set out with the goal of driving small increments of code that actually work. We needed a way to define what those small increments were, and the test framework gave us a harness in which to run tiny increments of code, set expectations about how the code would work, and see those expectations satisfied.

It is important to realize that Test-Driven Development is not about testing, or quality, because it is important to realize that quality is not achieved through TDD alone. Several studies have shown that software produced with TDD tends to have less bugs, but that is a side-effect of TDD and not the goal per se. In order to have quality we need to be able to verify that the software works the way the customer intends. We need a way to verify that it looks good, is usable, accomplishes work that the customer needs it to do, performs adequately, is free from obvious defects, etc. Test-Driven Development is not about these things.

Quality, in Agile, is achieved by working in small increments, by collaborating to set clear expectations up front, by using Test-Driven Development to build the software, and by performing various kinds of testing to assure that the product meets the goals we set early and continuously throughout the process. Test-Driven Development is only about how we build the software. We need other techniques to assure that the software meets our customers’ needs.

Comments

  1. Philip Schwarz says:

    Hi Adam,

    effective post, and reads well (IMHO), thanks.

    About quality, would it bring any value (to the target audience) to distinguish between external quality and internal quality, the latter coming into scope in passages like the following:

    Finally, we take a step back and look for indications that our design could be improved, the main one being duplication that is created by bits of code that do or say much the same thing.

    All the while we are seeking and exploiting small opportunities to improve and simplify the design of the code.

    Philip

  2. Philip Schwarz says:

    Recently I saw Codemanship’s Test-driven Development in Java which is a short demonstration of TDD in Java that shows how to build the fibonacci function with TDD.

    It seems to me that the fibonacci function is often chosen to give a very brief introduction to TDD, but I think there may be at least one disadvantage in using it as a first example for TDD newcomers.

    The Fibonacci TDD session always ends as soon as the coded function is clean and meets its functional requirements. TDD newbies can be forgiven for thinking that TDD stops when we have clean code that works, i.e. code that provides the required functionality, and has some of the internal qualities that will help us maintain/extend the code. In fact, one of the first reactions of TDD newbies is to accuse TDD of leading to code that does not meet external quality requirements, e.g. performance requirements: look, you ended up with a recursive function, that is a very poor choice of algorithm…if TDD was worth anything you’d have ended up with a function that caches its results, or that computes the result iteratively.

    What newbies need to be told is that you are not yet done just because you have clean code that works: you still need to work at getting the code to meet external qualities (e.g. usability, reliability, performance) and increase internal quality to the point that you’ll be able to produce the next version of the code with reasonable expense, i.e. improve the design.

    So while Kent Beck, in TDD by Example, tells us to ‘write a test, make it run, make it right’, making it right, does not just mean make it functionally right, and make it clean, but also, make it meet those non-functional requirements that are amenable to automated unit testing. And after doing TDD, other techniques are needed to get the code to meet those non-functional requirements that are not amenable to automated unit testing.

  3. Adam Sroka says:

    Hi Philip:

    Yes, I think you are absolutely right. TDD is about internal quality — the quality of the code. It is not about external quality. My point was that it is the external quality that traditional QA is primarily concerned with. We run the risk of overselling TDD if we allow the conversation to be about quality rather than design.

    As to your second comment:

    While I think that Jason Gorman’s video is excellent, I agree that Fibonacci is too short and simplistic to show how TDD evolves a design.

    Kent Beck released a series of videos through the Pragmatic Programmers that I think are much more effective in communicating these ideas. Plus, they are worth watching just to get a chance to see a master at work: http://www.pragprog.com/screencasts/v-kbtdd/test-driven-development

  4. Philip Schwarz says:

    I agree with you that Jason Gorman’s screencasts are great.

    About Kent Beck’s screencasts: I have watched them once. Will be watching them again soon. Mark Needham has been blogging about them:

    Kent Beck’s Test Driven Development Screencasts
    TDD: Call your shots
    TDD: Testing collections

  5. Joshua Lewis says:

    Great post, thank you.
    I have a similar (in intention) post on TDD here: http://joshilewis.wordpress.com/2009/11/16/test-driven-development-part-1/

    Basically the point of the post is that TDD is used to give us direction, and a way to discover when we’ve reached our destination (via the mechanism of a test).

Speak Your Mind

*