Skip to content
August 22, 2012 / Andrew

Unit Testing Calls to Static Methods

I wanted to introduce unit tests and TDD into a rather large Silverlight project. It already contained tons of calls to static methods, so it was pretty much impossible to write unit tests for code that consumed them. Here’s a simplified illustration of the problem and my solution.

Problem

Let’s say that messages are being shown to the user with code similar to this:

UserInteraction.ShowMessage("Here's a message!");

The static UserInteraction class does the actual work of interacting with the user.

public static class UserInteraction
{
	public static void ShowMessage(string message)
	{
		Console.WriteLine(message);
	}
}

Let’s start writing a simple class that will need to interact with the user.

namespace MockExample
{
	public class WorldGreeter
	{
		public void SayHello()
		{
			// TODO: Show message
		}
	}
}

First we should write a unit test that ensures this method calls ShowMessage correctly. We don’t want our test to execute the code inside UserInteraction though.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MockExample;

namespace MockExampleTests
{
	[TestClass]
	public class WorldGreeterTests
	{
		[TestMethod]
		public void TestHelloWorld()
		{
			// What to do here?
		}
	}
}

A unit test usually focuses on code in one class, and of course there’s no user to interact with during an automated run of a unit test. If you’re familiar with TDD, you know that mock objects are often used to isolate the code under test.

Unfortunately, ShowMessage is a static method, and I’m not aware of a free way to mock it in a Silverlight project. TypeMock Isolator and Telerik’s JustMock are a couple of non-free options to consider. I tried JustMock, and unfortunately at the time it couldn’t mock statics in Silverlight code.

Solution

Here’s all the source code in a .zip file.

Step 1: Create an interface.

public interface IUserInteraction
{
	void ShowMessage(string message);
}

Step 2: Get an IoC container.

I’ve been using Unity for this.

using Microsoft.Practices.Unity;

namespace MockExample
{
	public class IocContainer
	{
		public static UnityContainer Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new UnityContainer();
				}
				return _instance;
			}
		}
		private static UnityContainer _instance;
	}
}

Step 3: Move the work out of the static class.

The real work will be done by a new non-static class. The static class will use it (see next step).

static class UserInteraction
{
	public static void ShowMessage(string message)
	{
		// TODO: Reference an object that can do the work.
	}
}

class UserInteractionImplementation : IUserInteraction
{
	public void ShowMessage(string message)
	{
		// Do the work.
		Console.WriteLine(message);
	}
}

Step 4: Get a reference to the class that will do the work.

We’ll add this private property to the UserInteraction static class:

private static IUserInteraction Instance
{
	get
	{
		return IocContainer.Instance.Resolve<IUserInteraction>();
	}
}

…and use it in the ShowMessage method:

static void ShowMessage(string message)
{
	Instance.ShowMessage(message);
}

So the static class has a dependency on IUserInteraction, and it’s using the IoC container to satisfy that dependency. Now we need to tell the IoC container how to do that.

Step 5: Set up IoC container for production.

In production, we’ll have the code in our entry point tell the IoC container to return a real UserInteractionImplementation. Your entry point might be in App.xaml.cs for Silverlight/WPF or in the application start event handler in Global.asax.cs for a web app/service. This trivial example is a console app, so we’ll go to the Main method.

namespace MockExample
{
	class Program
	{
		static void Main(string[] args)
		{
			IocContainer.Instance.RegisterInstance(new UserInteractionImplementation());
		}
	}
}

We’ve registered it as a singleton, so it’ll keep the same object in memory and reuse it. This is far from being the only way to do it, as you can see in the Unity documentation.

Step 6: Set up the IoC container for testing, using a mock.

I’ve been using Moq for mocking.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MockExample;
using Moq;
using Microsoft.Practices.Unity;

namespace MockExampleTests
{
	[TestClass]
	public class WorldGreeterTests
	{
		[TestMethod]
		public void TestHelloWorld()
		{
			var uiMock = new Mock();
			IocContainer.Instance.RegisterInstance(uiMock.Object);
		}
	}
}

Hurray, we now have a mock object for the static method, and we haven’t broken the hundreds of other places in the code base that use the static method!

Step 7: Finish the test, and implement the method under test.

[TestMethod]
public void TestHelloWorld()
{
	// Arrange
	var uiMock = new Mock();
	IocContainer.Instance.RegisterInstance(uiMock.Object);

	// Act
	var greeter = new WorldGreeter();
	greeter.SayHello();

	// Assert
	uiMock.Verify(m => m.ShowMessage("Hello World!"));
}

Once we’ve seen that the test fails, we implement the method to make it pass.

public class WorldGreeter
{
	public void SayHello()
	{
		UserInteraction.ShowMessage("Hello World!");
	}
}

Here’s all the source code in a .zip file.

Criticism

This solution is an example of how not to use an IoC container. See also this description of Service Locator as an anti-pattern. I did it this way because:

Have you solved this problem before? How did you do it? Any questions or comments about this solution?

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s