Monday, 7 December 2015

Unit Testing Legacy Code

Adding unit tests to legacy code can be extremely difficult. There are a number of reasons for this, such as:

  • The code base is often added to on lots of separate occasions, usually over many years, which can lead to a lack of consistency in how things are done (e.g. code conventions can change over time, new versions of the language introduce new features, etc.).
  • Lots of different developers, often of widely differing ability, work on the code.
  • The "it's working so we'd better not touch it" mantra. We've all been guilty of this; sometimes if the code is working, we just leave it be, regardless of its quality.
  • Emergency patches are applied with the promise of "we'll come back and do it properly later": of course this never happens.

This can all add up to a code base that is not particularly amenable to unit testing. Classes are often tightly coupled, with little or no use of dependency injection, and liberal use of static methods.

However legacy code is usually the code most in need of unit tests, as they allow developers to carry out refactoring safe in the knowledge that the functionality of the refactored code has remained unchanged.

In order to break this catch-22 there are a few strategies I use when adding unit tests to a legacy code base. The two main ones are:

  • The abstract factory pattern to encapsulate object creation; a factory abstraction can then be injected into the class under test to decouple it from the dependency being created.
  • Simple classes (with interfaces) to wrap static methods; the interface can be injected as above.

The aim is to introduce hook points to the code so units (e.g. a class) can be isolated and therefore unit tested.

I'll walk through a few examples in a future post of where I have applied these patterns to a real code base.

1 comment:

  1. It's great that you outlined points 3 and 4, cuz I'm sure not everyone know that facts. As for testing, I left attempts long time ago. To be honest, it needs a lot of effort and time spending. Instead, i've been using https://jitbit.com/ for a while and I must say that I'm totally satisfy with that type of replacement. However, thx for the post and code, you've done a great job.

    ReplyDelete