Test-driven development involves testing and analyzing before the first line of code is written. Let’s take a look at it in more detail.
With agile development methods, teams can develop more efficiently and economically. Agile methods also include test-driven development. The development is not tested — the development follows the software testing.
In the classic linear understanding of software engineering, the place of a test is relatively straightforward: software, a system, or individual components are developed and then land in the hands of a software tester.
However, test-driven development (TDD) reverses this process. First, the tests are developed and written. Next, the individual test cases are then used to write the best possible source code.
In agile software development, this can not only accelerate processes but also delivers high-quality and low-maintenance code relatively quickly.
Advantages of TDD at a glance:
- Maintainable quality software
- No untested code
- Clean/testable architecture using TDD as a design strategy
- No/little redundancies through merciless timely refactoring
- No unnecessary code on stock
- Focus on the essentials
Software testing and TDD cycle
In test-driven development (TDD), tests are used to control software development. The sequence of this programming is cyclical:
- A test is written that initially fails.
- Exactly as much production code is implemented that the test runs successfully.
- Test and production code are refactored.
The tests are typically implemented using the XUnit framework in the same language as the production code. Tests that pass are represented by a green bar, unsuccessful ones by a red bar. This is why we speak of the “red-green-refactor” cycle.
The essence of the TDD approach
Test-driven development is still subject to the approaches that US developer Kent Beck founded with Extreme Programming. First, the software tester develops tests to check a single functionality. Ideally, a straightforward example is used at the beginning. Any errors can also be used in existing code.
This approach’s first software testing attempts fail and are marked in red. The code is then adjusted to pass the test so that the test that has now been passed is marked in green. The aim of the customization is to adapt the code as little as possible — and as elegantly as possible.
If test results are vetted by the software tester, then the code goes into refactoring, the third phase of Extreme Programming. In this step, code is further optimized, redundancies are removed, and abstractions are used.
Even in refactoring, the code runs through software testing. This ensures that the test continues to pass even after the changes have been made. From a logical point of view, every change is validated by the tests, which means that development is test-driven.
The code is then further optimized with tests that check the corresponding functionality of the unit. A unit is considered complete when the developers no longer want to or cannot improve or shorten the code, all tests are passed and no further meaningful tests can be carried out.
The tests for the unit are used again when the code is rewritten in the course of updates or adjustments. New tests can be added, but the code must always pass the old tests unless certain functionalities are declared obsolete.
This entire process is called the test-driven design cycle.
What distinguishes test-driven development from other software testing methods
Many testing strategies differ in the way they test software. In test-driven development, however, it is not the type of test played with but the placement of the test process. Therefore, test-driven development is not considered a different test method but a design principle.
Writing and designing the test before writing any code provides a unique advantage in agile development: you can see very early in the software testing lifecycle whether the code is functional.
Test-driven development is incremental. Each completed TDD cycle enriches the software with new capabilities — meticulously because each cycle section should not last longer than a few minutes.
Test-driven development as a design strategy
Writing the tests before the components you actually want to test is very distinctive of TDD. This is called test-first, and that’s why TDD isn’t a test strategy. It’s a design strategy.
Because if the test is written first, the interface of the component to be tested is already being used before it actually exists. The developer gets feedback on whether the design will also be usable as soon as possible.
The productive code is only implemented when a test requires it
Exactly enough code should then be written so that the test runs successfully. If too much productive code is written for a test, untested areas can cause refactoring problems.
With refactoring, the tests and the production code are cleaned up equally. The aim is to make the software simple, redundancy-free, and understandable. This phase of the TDD cycle immediately precedes the cycle starts: to write a specific test, it may be necessary to first anticipate a refactoring on the other tests or the production code.
The cycle does not overlap; each activity in test-driven development can be assigned to a section. No tests should be written in phases 2 and 3, and no productive code in phases 1 and 3. The code’s behavior is not changed during refactoring, i.e., nothing functionally changed during the tests (phase 1) or in the productive code (phase 2).
Conclusion
The principles that TDD unites are continuous design improvement, simple design, and test-first. TDD is a core Extreme Programming technique and is thus part of agile software development. It promises quality software and a significant upgrade of the software architecture thanks to the evolutionary design.