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.
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.