About
Subscribe

Self-testing code: The ugly duckling

In his third column for ITWeb, Martin Fowler, who is currently presenting his master classes at ObjectActive '99, examines the importance of testing and, therefore, self-testing code.
Johannesburg, 23 Jun 1999

Ever been to the design techniques` annual ball? The hot crowd is the UML group, wearing sharp, expensive outfits. Entity relationship diagrams wear suits, look a little on the grey side, but are still popular. (They claim they are just as good as the object techniques, but the object techniques are better dressed.) CRC cards turn up in sandals, patterns are always trying to convert you, and formal methods snub everyone else for the slightest crease or stain. In a corner, ignored by all, wearing stained and colour-clashing overalls, are the testing methods. Nobody wants to talk to them. But I`ve noticed that the parties that end in tears are usually the ones where the testing methods weren`t invited.

You can use design methods until you are blue in the face, but how you do your testing will probably have a bigger effect than teaching UML.

This is deadly serious. You can use design methods until you are blue in the face, but how you do your testing will probably have a bigger effect than teaching UML.

Develop self-testing code

A key technique is self-testing code. Testing is not something to start after you have finished coding, and test code is as important a deliverable as production code. (This self-testing code is unit test code, written by the developers themselves. You should have separately written system test code in addition to unit tests.)

I`m a great fan of incremental development. When adding new features I ask: "What is the smallest piece of new function I can add?" I then add that feature only, moving to a new feature when everything is complete including self-testing code. Development proceeds by small steps with testing code and production code proceeding in tandem.

It`s not unusual to write the test code before the production code. This helps to keep focus on what this incremental step involves. Another advantage is that the tests help you to concentrate on the interface for the new feature rather than the implementation.

With the test working I know I did what I set out to do. But there is a further essential step. Once your new feature test works, add it to your unit testing code base. As each feature gets added to the production code, a new test gets added to the test code. A project I`ve been working on has over 2 000 unit tests, and the unit test code is a quarter of the production code.

This battery of unit tests is invaluable. They must run easily and give a simple indication of whether they pass or fail. A test that produces a number, which is then checked manually against some list, is stupid. You should be able to run all 2 000 tests and know the result immediately.

Self-testing for future development

These self-tests are a golden for future development. They are easy to run regularly, even if they take a while. Run them every time you go off for a meeting or lunch and run a job at midnight which then mails you the result. If some part of the system breaks, the tests will quickly tell you. Try to run the full suite of tests whenever anyone integrates any code. Furthermore get people to integrate frequently. With incremental development you can easily integrate daily. Continuous integration and relentless testing make bugs show up early, when they are easier to find and fix. This reduces integration time.

I usually run tests every time I compile. It`s clearly not practical to run half-an-hour`s worth of tests on every compile, so I`ll choose a subset that focuses on the code I`m working on. Maybe I`ll have a 10-minute test suite for coffee breaks.

Unit tests are a great enabler. I love refactoring, making improvements to code without changing its behavior. Regular refactoring is essential to maintain design integrity. Doing refactoring with solid unit tests eliminates long and discouraging bug chases and is essential for performance optimization. Without the tests, it is hard to tell that a performance enhancement does not introduce a bug.

Getting self-testing to work

When I teach self-testing code a usual reaction is: "Well, this sounds reasonable - but I`ve got deadlines to meet." Self-testing code actually speeds up developing because it makes debugging faster. Previously, I spent more time and effort removing bugs than writing code. If you run tests regularly, you know which code contains the bug. Developers realise they are spending less time debugging and are developing faster. The tests enable easier refactoring, keeping the system design simpler, and allowing faster developing.

To introduce self-testing code, find people willing to give it a try. When they see their productivity improve, they will be the best endorsers of the technique. Mentors who practise the technique can pass it on to development staff. Make sure enough testing code gets written. A code coverage tool monitors how much of the production code is being exercised. Failing that, keep an eye on the ratio of test code to production code. Tests must be run regularly. If possible, enforce running all unit tests before checking in code or make sure there`s an automatic run of all unit tests daily when doing your daily build. (You do do a daily build, don`t you?)

If you don`t have self-testing code, start now. It may be the most important thing you do this year.

ObjectActive `99 follows on the success of the inaugural ObjectActive last year, and is sponsored by Futures and Sun Microsystems. It is being be held in Johannesburg at the VW Conference Centre from 22 to 24 June and in the Cape at Table Bay Hotel from 29 June to 1 July. For details, contact Derek Hughes on (011) 807-1340 or derekh@softwarefutures.com, or visit the ObjectActive Web site on http://www.objectactive.co.za

Share