Is it a Good Idea to Write Tests for Legacy Code?

A colleague of mine sent me an article on ArsTechnica that was a short discussion on whether it is a good idea to write tests for legacy code. This was made up from a collection of posts on Stack Exchange. The original question was as follows:

Suppose one had a relatively large program (say 900k SLOC in C#), all commented/documented thoroughly, well organized and working well. The entire code base was written by a single senior developer who no longer with the company. All the code is testable as is and IoC is used throughout—except for some strange reason they did not write any unit tests. Now, your company wants to branch the code and wants unit tests added to detect when changes break the core functionality.

Is adding tests a good idea? If so, how would one even start on something like this?

Original question posted by Paul over at Stack Exchange

It’s a good question, so I thought I would write down my thoughts on it. I am a firm believer in Test Driven Development (TDD) and this is much easier when you are working on a nice new green field project (writing a new system). Unfortunately we don’t always have the luxury of working on new systems and we have to maintain older legacy systems, or brown field applications. If you have a large brown field system, I personally do not think there is much value in getting your team of developers to sit there and wrap the whole system in tests. Whilst it may feel nice to know the application is covered in tests, the level of effort and expense in doing so is likely to be very high indeed. If the system has been around for a long time, then it is most probably working fine and your users are happy with it (this isn’t always the case, but is more often the case).

Legacy Systems
Legacy Systems

What I do feel is valuable though is adding some tests when you need to change/extend part of the code base. As the system already exists and you can’t reliable determine that the code is doing what it should be doing you can write what Michael Feathers describes in his book “Working Effectively with Legacy Code” calls characterization tests. A characterization test is:

Training : .NET 4 and 4.5 Features

In this article I have collated a few training links about .NET 4 and 4.5. I will keep adding to this page as I find other useful free resources. If you have any videos or articles that you feel would be useful here then please let me know in the comments and I will add them to the post. I would like it to be an archive of good material.

Training : C# 4 and 4.5 Features - Async, Dynamic etc
Training : C# 4 and 4.5 Features – Async, Dynamic etc

What’s New in .NET 4 and 4.5

New C# Features in the .NET Framework 4

What’s New in the .NET Framework 4.5

What’s New in.NET 4.5

C# (C Sharp) 4.0 new Features- Optional Parameters,Named Parameters

C# (C Sharp) 4.0 new Features – Dynamic keyword/type

Continuous Testing with NCrunch

Disclaimer: I currently do not own or have been given a license to NCrunch. I am forming my opinions of it based on the use of the 30 day evaluation license.

In this article I want to talk about a very useful tool called NCrunch. I have had a few people recommend the tool to me recently, so I thought I would check it out. I am glad I did. So, what is NCrunch? The description on their site explains this nicely.

Continuous Testing with NCrunch
Continuous Testing with NCrunch

NCrunch is an automated concurrent testing tool for Visual Studio .NET. It intelligently runs automated tests so that you don’t have to, and gives you a huge amount of useful information about your tested code, such as code coverage and performance metrics, inline in your IDE while you type.

On reading that I first though, hmm, well doesn’t visual studios test explorer do that, and it does, but this tools goes a step further. In essence NCrunch executes tests in the background whilst you work giving you continuous feedback. Initially I thought that’s not really such a big deal. One of the projects I am working in has 690 unit tests and because they are true unit tests, as in they don’t hit databases or external resources, then they only take 20 seconds or so to run. Even though this is the case you still get into the compile, run the tests, check the results, fix or carry on loop.

All Your Mocks are Evil!!

In unit testing, all mocks are evil! Now there’s a controversial statement to start a blog post with, but let me explain. I am writing this from my own experience as a software developer and a leader of software developers. This is the sort of thing that software religious wars are made of, so if you agree, or disagree, I would love for you to share your thoughts in the comments.


I think Mocking libraries, although very powerful, can enable developers to over complicate their unit tests. Unit tests should be short and easy to understand. I have lost count of the times where I have seen a developer mock out more than they need to because of excessive class coupling in their code. Just because you can mock out any object doesn’t mean that you should and avoid reducing excessive coupling.

Simple Dependency Injection

When you are working in the real world (especially on enterprise software) you will find yourself having to support and enhance an older code base. These code bases can vary quite considerably in quality. In the worst case you have legacy code that contains no unit tests. When you need to maintain and enhance this code you really should try to get some tests wrapped around the code, but this is easier said than done.

The code may contain lots of hard coded dependencies to objects that makes adding in clean, isolated unit tests difficult. These hard coded dependencies may access the file system, make database calls or access any other external resources making writing isolated tests difficult.

What do I mean by a hard coded dependency? Well, take a look at the following simple example.

using System;

namespace HardDependency
    public class ExampleClass
        public string GetText
                return "Hello, I am a hard dependency.";

    public class MyProgram
        public void DoSomething()
            ExampleClass example = new ExampleClass();

    class Program
        static void Main()
            MyProgram program = new MyProgram();

In this simple example we have a class called ExampleClass. This class has a property that returns a string. The class MyProgram has a method called DoSomething() that creates an instance of ExampleClass and calls the property to display the returned string. You may be thinking that nothing untoward is happening here, but what you see here is an example of a hard dependency, or coupling, between MyProgram and ExampleClass. Lets imagine ExampleClass is doing something much more complicated like reading data from a database. If you try to write a unit test to cover the functionality  of the DoSomething() method in MyProgram then that unit test will be making a database call. This is not a unit test. It may run fine on your development PC, but when you try to run these unit tests on your build server, it will also try to make a call to the database. A build server shouldn’t have access to an applications database. Also, what if that call to the database changes the state of the data, so that the next time you run the test, the data has changed, so the test fails. This is not a good situation as you now not only have tight coupling in your code, but you are also coupled to the state of the data in your database.

%d bloggers like this: