Mock me to my (inter)face

I learned an interesting, although in retrospect somewhat obvious, technique from Michael Feathers’s great book, Working Effectively With Legacy Code.

Suppose you have a class that can’t be unit-tested in any automated way because it has side effects or requires user input. Or, in the case of my application, it drives hardware that I don’t actually have readily at hand. NUnit and the like provide input to methods and test the resulting output. How can you run tests on something where the “output” is the motion of a sensor arm, or the “input” is a stream of weather data?

The short answer is that you really can’t, but that shouldn’t stop you from setting up unit tests.

The long answer is that you can hide the troubling class behind an interface, then implement the interface again with a class that can be tested.

To wit, let’s say this is your class now. It moves a data collector probe in 3D space, pulls input of some kind from the probe, and sends output now and then.


public class RealFoo
{
public RealFoo()
{
...
}
public void MoveDataCollectorProbe(int x, int y, int z)
{
...
}
public string GetInput()
{
...
}
public void SendOutput(string x)
{
}
}

This is going to be hard to test, because NUnit can’t see the probe moving around. But what you can test is some file I/O, so you can make a similar class thus:


using System.Diagnostics;
public class FakeFoo
{
public FakeFoo()
{
// probably doesn't do anything
}
public void MoveDataCollectorProbe(int x, int y, int z)
{
Trace.WriteLine ("TRACE: Moving data probe to coordinates x = " +x + ", y = " + y + ", z = " + z);
}
public string GetInput()
{
Trace.WriteLine ("TRACE: Getting input from probe.");
return "Typical Input Here.";
}
public void SendOutput(string x)
{
Trace.WriteLine ("TRACE: Sending output "" + x + "" to probe.");
}
}

Obviously the two classes have the same interface:


interface Foo
{
Foo();
void MoveDataCollectorProbe (int x, int y, int z);
string GetInput();
void SendOutput(string x);
}

Then you’d declare that both RealFoo and FakeFoo implement the Foo interface.

At this point, your application code can simply pass a Foo reference around all it likes. While under test, the object factory, or perhaps your own hardcoding, instantiates a FakeFoo. In actual use, or when you have hardware available, you instantiate a RealFoo:


public class FooFactory
{
public static Foo MakeFoo()
{
#if DEBUG
return new FakeFoo();
#else
return new RealFoo();
}
}

You can make the fake object as realistic as you like: randomize output, do intelligent things with the input, perform error checking, or throw exceptions to stress-test the calling code. The main thing is that tools like NUnit will have a fighting chance at picking up the trace stream and interpreting the results as pass or fail. As a bonus, you can do your development when the specialized hardware is unavailable or you’re not ready to run it.