«

»

Feb
13

Testing, testing

There’s a lot to be said for test driven development. Next to documenting the code, testing is the other bane of a developer’s life that prevents them from moving on and doing other, ‘more interesting’ work. All the better then that the approach to writing code should include the writing of test cases. Write some code, write a test case, make sure it passes, then OK, move on to the next bit. You build confidence in the existing code as you add to it.

Done this way testing doesn’t need to be all that boring. And one of the keys to this is the structure of the code you test. Listen carefully when you ask why testing is a bind and what you’ll find is that developers don’t necessarily mind writing test code, its the work in setting up the right data for the test cases that takes the time. And then updating it as the system evolves. What is happening here is that the unit test exercises an entire monolith of code which in turn requires more detailed configuration than just the one class being tested. And because so much code is being exercised, a change in any area can result in tests in other areas failing. And so the myth that testing is time consuming is perpetuated, because the unit test isn’t a proper unit test.

Producing testable code doesn’t take much additional foresight and in a way is connected to one of the key tenets of OO design – correct assignment of responsibilities. If classes are small and tightly focussed then they are easier to test. Likewise methods – are your methods properly decomposed and does each method have a single clearly defined purpose? If the answer is ‘no’ then you are building code that is harder to test. Moving up a level, you should be designing components with clear and clean interfaces, and using standard techniques such as the Business Delegate pattern to minimise coupling between them. Which, in turn makes it a relatively simple matter to implement component stubs to support the isolated testing of classes, which in turn wipes out much of that data set-up issue.

In short, difficulties in testing OO code can often be ascribed to the structure of the code. Here is a list of points to consider:

  • Write many small, focussed classes rather than fewer, big classes.
  • Restrict methods to performing a single purpose – decompose ruthlessly.
  • Refactor shared/duplicate code into super-classes or helper classes as appropriate.
  • Don’t expose private methods unnecessarily just to make testing easier – use something like the PrivateAccessor class from the JUnit Addons project.
  • Create interfaces for components to allow simple stubbing.
  • Avoid static methods wherever possible.
  • Use the Business Delegate class to minimise coupling between components.
  • Use JUnit to build tests, and Emma to check your coverage

And as I’ve touched on Emma, an excellent tool which allows you to see, line by line, which code has been tested and which has not, I shall finish by briefly discussing test coverage. How much of your code should you test?

Your quality department would probably say “100%” but unless you’re working in a high-risk area (for example, fly-by-wire flight systems for airliners) then you probably won’t have the resources to do this. My take on unit testing is as follows:

  • Don’t write unit tests for bean getters and setters (I’m assuming here that your getters and setters do only that, and contain no complex processing), but do make sure they are exercised.
  • Don’t write test cases to demonstrate that assertions are thrown correctly (you are using assert, aren’t you?).
  • Maximise test coverage on your framework code (errors here will affect your system across the board)
  • Prioritise test coverage on your functional code. Focus on the more complex, riskier and shared code first.
  • If you are back-filling tests on code that has already shipped, focus on those areas causing the most disruption to your customer or support team.

If you’ve written small classes with tightly focussed code, it is actually quite difficult to get your coverage beyond 90% anyway, and the cost of completing those few extra percentage points will, for most situations, far outweigh the benefits.

Next time, the importance of the method contract.

1 comment

  1. Leth says:

    I really wish test driven development had been drilled into us more in the first few years of my CS degree, hopefully the syllabus covers that now though.

Comments have been disabled.