Test Driven Development (TDD)

TDD_1_2.png

What is TDD?

Test-driven development (TDD) is a approach to development which is a ccombination of test-first development and refactoring. Test-first development means to write a test before you write any new feature that will fulfill that test. According to wikipedia,

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. This is opposed to software development that allows software to be added that is not proven to meet requirements.

Why TDD needed?

The primary goal of TDD is, it's specification and not validation. In other words, it’s one way to think through your requirements or design before your write your functional code. The goal of TDD is to write clean code that works without wasting much of the development time. Main benefits are,

  • Easy to understand the specifications
  • Takes much less time for debugging
  • Coder can prove that the code meets the requirements
  • Shorter development cycles

Test driven development cycle

code_driven_testing.jpg

  1. Add a test: In TDD, each new feature begins with writing a test for the feature. Write a test that defines a function or improvements of a function, which should clear the concept. To write a test, the developer must clearly understand the feature's specification and requirements. The developer can accomplish this through use cases and user stories to cover the requirements and exception conditions, and can write the test in whatever testing framework is appropriate to the software environment.

  2. Run all tests and check if new test fails: By running all the test we can validates that the test scope is working correctly, that the new test does not mistakenly pass without requiring any new code. The new test should also fail for the expected reason. This step increases the developer's confidence that the unit test is testing the correct constraint, and passes only in intended cases.

  3. Write the code: The next step is to implement some code that will causes the test to pass. The new code written at this stage is not perfect and may, for example, pass the test in a loop whole. That is acceptable because it will be improved and cleared in Step 5. The programmer must not write code that is beyond the functionality that the test checks.

  4. Run tests: If all test cases now pass, the programmer can be confident that the new code meets the test requirements, and does not break or degrade any existing features. If they do not, the new code must be adjusted until they do.

  5. Refactor code: The growing code base must be cleaned up regularly during test-driven development. New code can be moved from where it was convenient for passing a test to where it more logically belongs. Duplication must be removed. Object, class, module, variable and method names should clearly represent their current purpose and use, as extra functionality is added. As features are added, method bodies can get longer and other objects larger. The concept of removing duplication is an important aspect of any software design. In this case, however, it also applies to the removal of any duplication between the test code and the production code.

  6. Repeat: Starting with another new test, the cycle is then repeated to push forward the functionality. The size of the steps should always be small, with as few as 1 to 10 edits between each test run. If new code does not rapidly satisfy a new test, or other tests fail unexpectedly, the programmer should undo or revert in preference to excessive debugging. Continuous integration helps by providing revertible checkpoints.

Characteristics of a Good Unit Test

A good unit test has the following characteristics.

  • It should run fast. If the tests are slow, they will not be run often.

  • Separates or mock environmental dependencies such as databases, file systems, networks etc. These dependencies will slow the test process, and a failure does not give meaningful feedback about what the problem actually is.

  • The scope should be clear. If the test fails, it's obvious where to look for the problem. It's important to only test one thing in a single test.

  • If the tests require special environmental setup or fail unexpectedly, then they are not good unit tests. Change them for simplicity and reliability. Tests should run and pass on any machine. The "works on my box" excuse doesn't work.

  • Clearly reveals its intention. Another developer can look at the test and understand what is expected of the production code.

Conclusion

Test-driven development is an advanced technique that uses unit tests to drive the design of software. Its a continoius process that requires patience and practice.

dilbert_tdd.gif

References

This article is based on the popular book of TDD "Test-Driven Development by Example"