Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm about to take on the task of reimplementing an already defined interface (a set of C++ header files) in a relatively large and old code base. Before doing this, I would like to have as complete test coverage as possible, so I can detect reimplementation errors as early and easily as possible. The problem is that the already existing code base was not designed to be easily testable, with (very) large classes and functions, a high degree of coupling, functions with (many) side effects, etc.

It would be nice to hear of any previous experience with similar tasks, and some good and concrete tips on how you went about retrofitting automated tests (unit, integrations, regression, etc.) to your legacy code.

share|improve this question
1  
Step 1: Search Stack Overflow. The question has been asked. Many, many times. –  S.Lott Jan 27 '11 at 11:14
add comment

4 Answers 4

First of all, get and read Working Effectively With Legacy Code by Michael Feathers - it is an indispensable aid for such tasks.

Then, a few notes:

  • do you have a precise specification / contract for the interface, or do you practically only have the existing implementation as "specification"? In the former case it is easier to do a complete rewrite from scratch, in the latter it is difficult to impossible.
  • if you want to reimplement the interface, the most useful way to spend your testing resources is to write tests only against the interface. Of course, this does not qualify as unit testing in the strict sense, rather functional/acceptance testing, but I am not a purist :-) However, these tests are reusable and enable you to directly compare results from the two implementations side by side.
  • overall, I would favor refactoring the existing code rather than rewriting from scratch, unless it is completely unmaintainable. (But in this case, how are you going to write unit tests against it anyway?) Check out this post from Joel for a more detailed discussion on the subject. Having created a set of acceptance tests against the interface gives you a thin, but useful safety net, against which you can start cautiously refactoring the existing code towards making it unit testable (using the ideas from Feathers' book).
share|improve this answer
    
I would +3 this if I could. WELC is an essential read and definitely go for a refactoring... –  Johnsyweb Jan 27 '11 at 8:42
    
One minor comment on the 2nd point is that for legacy systems, testing should be done according to the characterization test mindset. That is, faithfully capture the current behavior of the software, and refrain from changing the behavior even if some of the test results seem strange or not agreeable according to unit testing mindset. (Btw this idea also comes from the author of WELC.) –  rwong Jul 28 '12 at 6:46
    
@rwong, indeed. Without a detailed specification, or a knowledgeable product owner, it is impossible for the developer to decide whether a specific behaviour of the program a) is intentional and required, b) was unintentional but by now users depend on it, c) a bug which actually harms users, d) a bug totally unnoticed up to now. In the first two cases, "fixing" it would actually hurt users, and in the last case, the fix - although theoretically correct - would provide no visible benefit. –  Péter Török Jul 28 '12 at 13:07
add comment

Retro fitting tests onto an old code base can be quite difficult if it is monolithic in design.

If possible (do you have the time/money), one way to move forward would be refactoring the code into more testable units.

share|improve this answer
add comment

Best method is know is the Mikado Method. http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ This is just the generalization of a simple technique but it's the only way I know to start improving code quality in a big code base without taking unnecessary risks.

WEWLC is also a very good book about it but being written in C++ is not always useful with Java or Ruby code.

share|improve this answer
add comment

I would like to add one link. There are few examples of not so easilly testable implementations re-factored into more xUnit friendly code. As for general approach go try already mentioned links (Joel post, Working With Legacy code

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.