Daniel Brown Page 1

Test Driven Development (TDD)

Introduction

Test Driven Development (TDD) is a software development technique consisting of short iterations based on automated unit tests. Test Driven Development turns other traditional software development methodologies on their head. Instead of writing your code first and then testing as an afterthought, the test is written before the functional code. Therefore the old paradigm of design, implement and then test becomes design, test then implement. TDD is derived from agile development technologies, specifically extreme programming (XP) proposed by Kent Beck in the late 1990s. Kent Beck was also credited with discovering TDD as a technique in 2003 when he published a book called Test Driven Development: By Example. Other development approaches including Scrum and Rapid Application Development (RAD) incorporate the TDD approach to coding. Although TDD primarily focuses its attention on unit testing, integration and acceptance testing should not be overlooked in the TDD process. Integration testing needs to be incorporated to ensure the small unit test work together and acceptance testing ensures the software meets customer requirements.

Motivation

The main goal of TDD is to prove code works as it should by eliminating bugs as coding develops. This is done by driving development with unit testing to ensure exhaustive test coverage. Traditional testing methods open the door for developers to think unexpected behaviours and half finished features are acceptable (Cunningham, Extreme Programming Pocket Guide). However, failures with TDD should only represent the last few minutes of changes to the system. If you are spending too much time testing in the TDD process then test less and if you are not finding enough bugs test more. The less time between introducing a defect and noticing, the less time needed for debugging. In addition “The cost of fixing things increases profoundly the longer we wait” (Ron Jeffries). TDD helps software developer produce high quality working code that’s maintainable and most of all reliable.

Test Driven Development Stages

Test Driven Development combines test-first development with the process of refactoring. Firstly a unit test is added to test some function of the system. A test which cannot be implemented highlights a poorly defined requirement before coding even begins. Indeed, the TDD process makes the developer focus on the requirements before writing code whereas with traditional resting the requirement could be somewhat overlooked. The initial test should fail as there is currently no code implemented for the test to pass. In some cases the test may not even compile until the feature has been implemented. The failing of the initial test code is important else you will never know if you have implemented a function correctly. Although writing a test which fails can be disheartening, a sense of achievement is achieved when tests pass. The programmer then writes just enough code in order to pass the test. By this process, scope creep is prevented. With the traditional design, implement and test philosophy it is easy to get carried away programming and implement features which are not necessary. As the test states explicitly what the system is supposed to do the programmer becomes more focused on coding features individually. The test is then run in order to ensure the function has been implemented correctly. If the test still fails the code needs to be changed and re-tested. If the test passes, the programmer goes into the refactoring stage before iterating through process again. The TDD process is illustrated below:

The TDD coding technique only has two simple rules which need to be adhered to:

·  We write code only if a test has failed.

·  Eliminate Duplication

These two rules have implications for the technical coding. The code must be designed on the spot, while constant feedback is provided between design decisions. This is why Test Driven Development is seen by some as a design technique as well as a testing technique (Sinaalto, 2006). Developers focus on the system design before coding as well as the design of code through the process of refactoring. The tests must be written by the developer as it is unlikely they will be able to wait 20 times per day for a member of the testing team to implement them. Automated testing tools, such as JUnit, can provide automation to the testing process. The development environment must provide rapid response to small changes. The two rules stated above imply an order to the tasks of programming. (Beck, 2003) proposed the red/green/refractor programming mantra.

1.  Red – Write a test that doesn’t work.

2.  Green – Make the test work quickly. Maybe committing coding sins in the process.

3.  Refractor – Eliminate all the duplication and bad coding practises needed to get the test working.

Refactoring is an important feature of TDD. This is the disciplined process of improving the design of code without changing its behaviour (O'Reilly, 2003). The main goal of refactoring in TDD is to eliminate duplication however developers may also strive to:

·  Improve code readability

·  Simplify the code structure

·  Change code to adhere to coding practices

·  Improve performance

·  Improve maintainability

·  Improve extensibility.

For example, splitting large functions into smaller ones not only improves readability but allows code to be reused .The process helps to produce highly cohesive and loosely coupled designs. Many IDE’s, such as NetBeans have features for automated refactoring. These include extracting the interface from a class to aid extensibility, encapsulating variables and replacing the instances with appropriate getter and setter methods and changing method parameters. The refactoring features provided by NetBeans can be seen by clicking this link. Refactoring only makes small changes to code but these small changes can have a big impact when coding becomes complex. The process is particularly relevant to XP where system designs emerge as the project grows. Code can become unruly at times hence refactoring can help to prune away bad coding traps. Refactoring can help to support collective code ownership as adhering to coding standards and practices as code written by other developers becomes easier to understand. Thus, it gives developers the power to change any code within a project when necessary, rather than being reliant on other developers.

Advantages

Test Driven Development is a fundamental concept of extreme programming. Therefore, although TDD has benefits in its own right some advantages stem from supporting XP values. The main values of XP are listed below:

·  Communication

·  Feedback

·  Simplicity

·  Courage

Direct Implications:

Quality Assurance becomes “pro-active” rather than “re-active” and therefore the defect density of the code is reduced. Programmers become more focused on the system requirements by firstly asking themselves why a feature is needed before proceeding with the implementation. By this process, the developer can identify badly defined requirements as producing a unit test for them becomes taxing. Unit tests are the executable specification for the system and can therefore be incorporated into system documentation. This can help increase developer understanding of parts of the system and therefore helps to support collective code ownership. As a result, changes to code can be made by any developer rather than the only developer who understands the code.

Supporting XP Values:

TDD helps to support some fundamental concepts of extreme programming. Although these values are directly related to XP they are values to strive for in any methodology. TDD maximises both customer and system feedback. Constant system feedback stems from vigorous unit testing for each function of the system. Continuous feedback can provide a sense of accomplishment to channel the development forward. TDD has a short development cycle to support regular system releases. As a result the system is kept in prime working condition and so developers are more likely to involve customers in the development process. This in turn results in increases customer feedback. The short release cycle means customers are more likely to see a return on their investment and there is likely to be greater acceptance of the system as the company has to adapt too few big changes. Not only this but developers are able to respond to feedback efficiently. Most importantly operational bugs can be detected more rapidly reducing the cost of fixing them. Due to system features being implemented one by one this in turn assumes simplicity. The customer has more control over the system being developed rather than if big changes are made at once. Simplicity also helps to reduce scope creep as the developer is less likely to implement features which are not necessary. TDD helps developers focus on implementing the current requirement and hence eliminates fear. By using the word “fear” in this context, I am referring to fear in a ‘cant see an end from the beginning’ sense. (Beck, 2003) describes the negative effects fear can have on software developers:

·  Makes developers tentative

·  Makes you communicate less

·  Makes you shy away from feedback

·  Makes you grumpy.

Needless to say, eliminating fear is essential for a successful software development project.

Limitations

As with any development technique, TDD has its limitations. Firstly, TDD is difficult to use in situations where full functional tests are required to determine success or failure of a system. Examples include testing user interfaces and programs with database interaction. Project management support is essential else management will feel time spent writing tests is wasted. The vast number of tests required means tests themselves become a large maintenance overhead of the project. Not only does the code need to be maintained but so do the unit tests. Tests which repeatedly fail could prove expensive to pass. There is a danger that a poor design, coding strategy or poor architecture could lead to late changes and make multiple tests fail. Thus, the cost of fixing errors increases. Tests created in the TDD environment are commonly written by the developer. Therefore, the tests and code may share the same “blind spots”. For example, a developer does not realise that input parameters for a certain method must be checked. It is likely neither the code nor test will verify these parameters. This could result in bugs being present for this particular system feature of worse still features may not be implemented at all. Finally, a high number of passing unit tests may bring a false sense of security. Therefore the vast numbers of unit tests are not a substitute for integration or acceptance testing.

References

1.  Sinaalto, M. (2006) The Impact of Test-Driven Development on Design Quality. ITEA Information Technology

2.  Beck, K. (2003) Test Driven Development: By Example. United States of America: Addison-Wesley.

3.  Shore, J., Warden, S. (2008). The Art of Agile Development .United States of America: O’Reilly.

4.  Cunningham, W. (2003). Extreme Programming Pocket Guide. O’Reilly: United States of America

5.  Beck, K., Andres, C. (2004) Extreme Programming Explained: embrace change 2nd edition. United States of America: Pearson Education

Online References

6.  http://www.smartagile.com/2007/09/test-driven-development.html

7.  http://www.agilealliance.org/system/article/file/1423/file.pdf

8.  http://en.wikipedia.org/wiki/Test-driven_development

Test Driven Development