php[architect] logo

Want to check out an issue? Sign up to receive a special offer.

Why TDD is based on testing first

Posted by on March 11, 2010

Test-Driven Development is a design technique that is wildly spreading in the PHP world. One of the pillars of the red-green-refactor mantra is that every new feature development starts with a failing test, which has to be written before the production code it will exercise. Test-first was already an Extreme Programming practice before the formalization of TDD, having now become a very important part of it.

The most immediate advantage of testing first resides in ensuring that a regression test suite for the application will always be in place by incrementally developing it: if you favor incremental approaches to software development over the waterfall model, you won’t have difficulties in understanding that the application’s testbed should grow with the production code.
The quality of the test suite in exposing defects is also in the spotlight in a test-first approach: because the test cases are written before their related functionalities are implemented at all, they usually do not produce false negatives, failing any time the production code does not meet the expectations. This is true at the beginning – when the production code does not exist yet – but also in any subsequent development phase, when bugs may otherwise be introduced by the code changes of the very development process.

Tests also drive the design of a component (usually a class, but also a whole functional unit in the case of acceptance tests) by writing down its responsibilities and its API in an executable model, which as long as the suite is not broken is in sync with the production code.  That is why a test suite acts also as documentation for developers as it is the first place to look for a specification of a class’s behavior. Unit tests also specify the SUT collaborators’ contract, in the definition of stubs and mocks expectations; in an electronic metaphor, fully characterizing the behavior of the unit at its terminals. And they can do this before their subject exists, highlighting the Api’s faults or dangerous dependencies: while the implementation will always be changing, well written tests are focused on the definition of fixed points: the protocols used by objects to communicate.

Dependency Inversion (and the primary technique for achieving it, Dependency Injection) is an example of a principle that can be enforced by unit tests, because they rapidly become simply too hard to write without it. The result is that a testable application has no other chance than be a well designed application, with external dependencies already exposed and a consistent interface. Think of it: testing is essentially about transplanting components in a foreign environment, while keeping up the survival rate to nearly 100%. The simpler testing is, the more decoupled from their peers the components are. Again, testability promote insulation from external conditions – random variables, date and time, databases.

Finally, the test-first approach forces components and classes implementation to be actually testable in an automated framework, PHPUnit in the majority of PHP applications. This should not be taken for granted: trying to retrofit a test suite into an application it’s very difficult if the design does not allow it, while as shown earlier maneuvering the architecture with incremental tests is actually beneficial.

Image credit: Test tubes and other recipients in chemistry lab, courtesy of Horia Varlan.

Marco is the keeper of keys and Chief Garbage Collector at Blue Parabola. He can be found on Twitter as @mtabini.
Tags: , , ,

Leave a comment

Use the form below to leave a comment: