Thursday, July 23, 2009

Real programmers write unit tests (part 3)

Ok, you know the drill: you have to modify a feature of Program X and to do this you have to modify a class – lets call it UglyThing – and this class is a mess and it has no unit tests. This class has Efferent coupling through the roof and large methods that are really difficult to understand and work with. It feels like you are going to have to build the whole application by hand just to set things up for unit testing this class. What is a pragmatic programmer to do ?
In my situation at work I don't have any choice because the development process requires me to have unit tests for new or modified code. In a more permissive environment I might be tempting to skip the unit tests. However, if the code really is that bad skipping unit tests is really not a good idea.
Of course the first thing to do is to analyze the code carefully. In the context of a commercial application you really have to be cautious about any modifications you make to the code. Yet, sometimes a few well chosen simple and safe modifications can do the trick. Other times, techniques like Introduce middle man may be required. In more extreme cases you may have to turn to other techniques.

Extract static method

In OO programming adding static methods normally is something that you want to minimize. However, if you have reviewed the code and have been unable to find more conventional ways to modify the class to add unit test in the context of your current project compromise are in order. This may be a case where using static methods could help. In practice I see different variations on this theme:
Sometimes a class has one central method that does all the work and that could have been static from the start. In Java I extract the body of this large method to a static method with package visibility. I use the minimum visibility required to write unit tests for this in another class in the same namespace (Java package). Sometimes one has to add some of parameters to make this work. Often more parameters than the maximum that I would normally recommend. However, since this method is not part of the public API of the class I think this is an acceptable compromise. The last step is to replace the original code by a call to the static method. Now you can write a bunch of unit tests (possibly using parametric tests) for this method (the static version). It is now safe to perform actual functional modifications to the code for your new feature.
In some other cases it is not possible to extract whole methods and one has to limit the extracted code to portions of the original code. Even this will often be sufficient to add an adequate level of unit tests and proceed safely with the functional modifications.

Parting comments

Next time I will talk about the Layers architectural pattern. A layered design is a great way to set the stage for unit tests in some situation where unit tests are sometimes difficult to implement.

No comments:

Post a Comment