How to Mock Singletons and Static Methods in Unit Tests

Martin Rybak
4 min readMay 31, 2018

So you’ve had enough. That aging codebase of yours is just too darn fragile to work on. Everytime you fix a bug or add a new feature, something unexpected breaks. Your manual test plans aren’t thorough enough to catch these regressions, so the only way you find out about them is through angry customers. By the time your support team hears about them and they are triaged, groomed, prioritized, entered into a sprint, and finally fixed, it could be weeks. Not a great recipe for a successful product.

You already know that automated unit tests guard against regressions by constantly testing your code at the lowest level, but your legacy codebase is a mess of singletons and static method calls that are impossible to mock. Or are they? Here are some techniques you can use to make that code testable without making drastic (and risky) changes. The examples shown are written in C# but the concepts should apply to any object-oriented language.

Mocking Singletons

Here is an example of C# code that calls out to a singleton. How can we write a unit test that verifies that calling Bar() actually invokes DoIt()?

public class Foo
{
public void Bar()
{
Helper.Instance().DoIt();
}
}

We assume that Helper implements the IHelper interface. If it does not, and the class is not modifiable, use the technique shown in the Mocking Static Methods section below.

Let’s create a private member variable to hold onto an instance of IHelper, and a constructor that sets that variable. This is known as the constructor form of dependency injection. We will use this constructor in our unit tests to inject a mock version of IHelper and verify that DoIt() was called. However, the trick to not breaking the current implementation is to also provide a default constructor that gets its value from the existing singleton.

public class Foo
{
private readonly IHelper _helper;
public Foo()
{
_helper = Helper.Instance();
}
public Foo(IHelper helper)
{
_helper = helper;
}
public void Bar()
{
_helper.DoIt();
}
}

We can use constructor chaining to avoid duplicating code:

public Foo() : this(Helper.Instance())
{
}

Now your code is testable, but perfectly backwards-compatible! Here is what a unit test would look like using Xunit as the test runner and Moq as the mocking framework:

using Xunit;
using Moq;
public class FooTests
{
[Fact]
public void Bar_Invokes_Helper()
{
var mock = new Mock<IHelper>();
mock.Setup(x => x.DoIt());
var foo = new Foo(mock.Object);
foo.Bar();
mock.VerifyAll();
}
}

Mocking Static Methods

Free tools like Moq can only mock interfaces or virtual/abstract methods on classes with a public default constructor. If you need to truly mock static methods, you need to use a commercial tool like Microsoft Fakes (part of Visual Studio Enterprise) or Typemock Isolator. Or, you can simply create a new class to wrap the static method calls, which itself can be mocked.

Languages differ in this regard. Java developers can use PowerMock. In Objective-C, static methods, a.k.a class methods, can be mocked using OCMock.

Here is an example of code that calls a static method on the Helper class:

public class Foo
{
public void Bar()
{
Helper.DoIt();
}
}

Let’s create a new class called HelperWrapper that implements IHelper and wraps the static method call:

public class HelperWrapper : IHelper
{
public void DoIt()
{
Helper.DoIt();
}
}

Back in Foo, we create a constructor that accepts an IHelper instance for testing, and a default constructor that creates a new instance of HelperWrapper. (Ideally, you would use a DI container for this). Your class is now testable, and nothing is broken in your calling code.

public class Foo
{
private readonly IHelper _helper;
public Foo() : this(new HelperWrapper())
{
}
public Foo(IHelper helper)
{
_helper = helper;
}
public void Bar()
{
_helper.DoIt();
}
}

Testing Your Own Static Methods

What if you want to write a test for one of your own static methods, which itself calls out to other static methods?

public static class Foo
{
public static void Bar()
{
Helper.DoIt();
}
}

In this case, we can create an overload of the method under test that accepts an IHelperWrapper, and use the original method to create a concrete HelperWrapper to pass into that method. This technique is called the method call form of dependency injection.

public static class Foo
{
public static void Bar()
{
Bar(new HelperWrapper());
}
public static void Bar(IHelper helper)
{
helper.DoIt();
}
}

And here is the corresponding unit test:

using Xunit;
using Moq;
public class FooTests
{
[Fact]
public void Bar_Invokes_Helper()
{
var mock = new Mock<IHelper>();
mock.Setup(x => x.DoIt());
Foo.Bar(mock.Object);
mock.VerifyAll();
}
}

Hopefully these techniques have given you some inspiration for tackling what can seem like an untestable legacy codebase. Using them, your team can start writing some tests to verify critical functionality without a drastic rewrite of your application. Remember though, that unit tests are only valuable if they are actually run. The best way is to use a build server to require a successful build and passing unit tests as a precondition for merging a code branch. Good luck!

--

--