An Introduction to Test-Driven Development

For the past 6 months I have been using Test-Driven Development (TDD) on a new project. It has made such a difference to the quality of my code, that I feel I just have to share it's benefits with those who may not have heard of it. TDD reverses the normal order of testing as it requires developers to create automated unit tests before code is written not after. This takes some getting used to, and it can be quite difficult to resist the urge to write code first and then a test, but it really is essential to test first in order to gain the full benefits of TDD. The beauty of this is that it allows you to concentrate on what you want the code to do before you concentrate on how to implement it.

Test-Driven Development Cycle

To use TDD, you need a unit testing framework such as JUnit for Java. The first thing to remember about TDD, is that you shouldn't write a single line of code without first creating a test for it. Therefore, TDD is a constant cycle of creating tests, then writing the code to pass them. Each test contains an assertion that is either true or false, so that a test can only pass or fail, thus enabling the tests to be fully automatic and not require developers to trawl through logs. Development is therefore often carried out in the following way:

  • Add a test

    Before implementing a new function or improvement to an existing function you should write just enough of a test to fail. It should fail on the first run because you haven't implemented it.

  • Run all tests and see if the new one fails

    It is important that the new test fails to start with to make sure that it wouldn't blindly pass regardless.

  • Write enough code to pass the new test

    You should write only enough code to pass the test. This reduces the chances of untested code.

  • Run all the tests and see if they pass

    If the test passes then you can add another test at step 1 ready for further code to be tested, or go to step 5 once you are happy that the implementation is complete and fully tested.

  • Re-factor Code

    If all the tests pass, then you can be confident that refactoring the code will not break it. If it does break, then you can easily spot this and correct it.

Tips for TDD

There are a number of tips that can help improve your success with TDD:

  • Design for testability

    This can make things much easier to test and can make the design much cleaner.

  • Don't break the encapsulation of your classes

    It is important to respect the encapsulation of the class so that the tests are not reliant on the implementation details. Therefore, you shouldn't test private methods directly, instead just thoroughly test the public methods and try to exercise the private methods as far as is needed through the public methods.

  • Create extra tests to find suspected bugs

    While you can use a debugger to find bugs, it is important to complement this bug finding with extra unit tests to ensure that the bug doesn't come back and to improve the robustness of the tests.

Benefits of TDD

TDD normally means that you end up producing a lot more code because of all the testing, but I have found that this dramatically improves the quality of the code and design. I have also found there to be a definite speed improvement to my development work, because I am not spending so much time debugging. In addition the following benefits are generally considered to be a hallmark of TDD:

  • Helps you to concentrate on the expected behaviour of classes and their methods. So that you can focus on how you would like them to work and be used, without worrying about the implementation details.
  • Gives you greater confidence to alter the implementations of the methods without breaking them or the programs using them. This in particular is invaluable. All too often we can be put-off cleaning up code or tweaking it to improve efficiency, because we are worried about introducing bugs.
  • Isolates bugs early rather than suffering from a mass of hard-to-locate bugs, thereby reducing the amount of time spent debugging.
  • Makes project time planning easier as you are not so reliant on guessing the amount of time required at the end of a project to test and debug.
  • The tests document extensively how to use the libraries,classes,functions,etc.
  • The tests can't get out of sync with the production code.

Where Now?

Unfortunately I have found that information about Test-Driven Development on the internet is a little chaotic. However, I do like, which has a good RSS feed and I particularly like their Web Links, which has a great selection of articles. I firmly believe that TDD can, with patience, improve virtually anyone's code, and certainly recommend that you give it a good go before making up your mind.

Creative Commons License
An Introduction to Test-Driven Development by Lawrence Woodman is licensed under a Creative Commons Attribution 4.0 International License.

Share This Post


Related Articles

Modula-2 Compilers on CP/M

Modula-2 is a great language in general and is a good choice for programming on CP/M. There are three good compilers available for CP/M which all require a Z80 processor and we'll compare each in turn...   Read More

Is SUBLEQ the Right Choice for a VM?

SUBLEQ is an interesting architecture because of its simplicity, adaptability and power. It is therefore an attractive choice for a simple virtual machine. However, this comes at a cost which we will...   Read More

80 Columns in Software on the Commodore VIC-20

If you have good eyesight, a well-tuned display and patience it is possible to use 80 columns in software on the VIC-20. This is really just an experiment but considering the limitations of the Vic I ...   Read More

64 Column Text Mode on the Commodore VIC-20

With a little lateral thinking and by putting the television on its side we can create a 64 column sideways text mode on the VIC-20. This article will demonstrate this and show how it is done. Previo...   Read More

Getting the Address of BASIC Variables on the VIC-20

Getting the address of a BASIC variable can be useful if you want to pass data to a machine code routine or want to access the bytes of a variable directly to improve speed and reduce garbage collectio...   Read More