Test-Driven Development, or TDD, is one of the best practices of eXtreme Programming (XP). TDD has a lot of impact on the way in which development testing (also outside of XP, particularly with iterative and agile development) is organised these days. It is an iterative and incremental method of software development, in which no code is written before automated tests have been written for that code. The aim of TDD is to achieve fast feedback on the quality of the unit.
Development is carried out in short cycles, in accordance with the above scheme:
Creating a test
- Write a test
TDD always begins with the writing of test code that checks a particular property of the unit.
- Run the test (with fault)
Execute the test and check that the result of the test is negative (no code has yet been written for that piece of functionality).
Encode and test
- Write the code
Write the minimum code required to ensure that the test succeeds. The new code, written at this stage, will not be perfect. This is acceptable, since the subsequent steps will improve on it. It is important that the written code is only designed to allow the test to succeed; no code should be added for which no test has been designed.
- Execute the test and all the previously created tests
If all the test cases now succeed, the developer knows that the code meets the requirements included in the test.
- Clean up and structure the code
The code is cleaned up and structured without changing the semantics. The developer regularly executes all the test cases. As long as these are successful, the developer knows that his amendments are not damaging any existing functionality. If the result of a test case is negative, he has made a wrong change.
The application of TDD has a number of big advantages. It leads to:
- More testable software
The code can usually be directly related to a test. In addition, the automated tests can be repeated as often as necessary.
- A collection of tests that grows in step with the software
The testware is always up to date because it is linked one-to-one with the software.
- High level of test coverage
Each piece of code is covered by a test case.
- More adjustable software
Executing the tests frequently and automatically provides the developer with very fast feedback as to whether an adjustment has been implemented successfully or not.
- Higher quality of the code
The higher test coverage and frequent repeats of the test ensure that the software contains fewer defects on transfer.
- Up-to-date documentation in the form of tests
The tests make it clear what the result of the code should be, so that later maintenance is made considerably easier. The theory of TDD sounds simple, but working in accordance with the TDD principles demands great discipline, as it is easy to backslide: writing functional code without having written a new test in advance. One way of preventing this is the combining of TDD and Pair Programming; the developers then keep each other alert.
TDD has the following conditions:
- A different way of thinking: many developers assume that the extra effort in writing automated tests is disproportionate to the advantages it brings. It has been seen in practice that the extra time involved in test-driven development is more than made up for by the gains in respect of debugging, changing the software and regression testing.
- A tool or test harness for creating automated tests. Test harnesses are available for most programming languages (such as JUnit for Java and NUnit for C#).
- A development environment that supports short-cycle test-code-refactoring.
- Management commitment to giving the developers enough time and opportunity to gain experience with TDD.
For more information on TDD, refer to [Beck, 2002]
TDD strategy for testing GUI
TDD also has its limitations. One area where automated unit tests are difficult to implement is the Graphical User Interfaces (GUI). However, in order to make use of the advantages of TDD, the following strategy may be adopted:
Divide the code as far as possible into components that can be built, tested and implemented separately.
Keep the major part of the functionality (business logic) out of the GUI context. Let the GUI code be a thin layer on top of the stringently tested TDD code.