Much have been said about the singleton pattern, a short visit to Google shows that its mainly about why not to use them. However, for some reason, in all projects I have seen up to date I found quite a few usages of this patten. In fact in most places, this pattern is over used extensible. I'm guessing this is mainly due to the ease of implementation, and the fact that in most systems one can find several classes which are only instantiated once. (i.e. we only need a single instance in the system)
This post is NOT about whether singleton are good or bad, for me that's not an interesting question. In realizing that most people use them, my goal in this post is just to show some useful tips on how to actually handle them during tests .
But first lets look at a common implementation of the singleton (taken from Wikipedia):
public sealed class SingletonThis implementation poses 2 testing problems that need to be addressed:
{
private static readonly Singleton instance = new Singleton();
static Singleton()
{
}
private Singleton()
{
}
public static Singleton Instance
{
get { return instance; }
}
}
- A private constructor - When writing tests, our main goal is to make them independent. Therefore we prefer that each test case will work on a different instance to avoid any chance one test will affect another.
- The static Instance method - its a valid assumption that much of the code will access the singleton using the Instance method. And it being a static method makes it harder to inject a fake instead of the singleton object.
There are several approaches for bypassing these issues:
1) Use reflection - either to create a new instance each test, or maybe to clear the created instance at the end of the test. (a good summary can be found here).
2) Decouple the business logic, from the creation logic - and test the business logic separately. A IOC container is a common technique for doing this, but a simple factory will do just as well.
3) expose some special method for testing, allowing to tweak the internal field - a simple setter sometimes goes a long way.
and I'm sure that there are more ways. to skin this cat.
I, however, prefer to leverage my tools as much as a I can. Specifically lets see how the Isolator (yeah a big surprise) can help me on this.
Scenario one - Faking a Singleton Behavior
You need to test a class which uses the singleton. During the test you need the singleton to behave in a manner which is very hard to simulate using the real production code (of the singleton). you would like to use a mock however its hard to inject the mock into the code since the static Instance method is had to mock using conventional approaches. In this case you can use the Isolator for setting a fake behavior and mocking the static Instance Method. Here is an example:
[TestMethod]
public void FakingSingleton()
{
// Create a fake instance
var fakeSingleton = Isolate.Fake.Instance<Singleton>();
// Set the faked behavior
Isolate.WhenCalled(() => fakeSingleton.SomeMethod()).WillReturn(7);
// Inject the fake into your production code
Isolate.WhenCalled(() => Singleton.Instance).WillReturn(fakeSingleton);
// Execute the test
var actual = Singleton.Instance.SomeMethod();
Assert.AreEqual(7, actual);
}
Scenario two - Testing the singleton class
Using the same technique we would like to test the singleton internal logic. However since the constructor is private its harder to created new instance each test. again Isolator can be used:
[TestMethod]
[Isolated]
public void SomeMethodTest()
{
//Just a cool way to create a regular instance instead of using reflection.
var fakeSingleton = Isolate.Fake.Instance<Singleton>(Members.CallOriginal);
//use this if you want your test to look similar to production code
Isolate.WhenCalled(() => Singleton.Instance).WillReturn(fakeSingleton);
var actual = Singleton.Instance.SomeMethod();
Assert.AreEqual(5,actual);
}
While all this examples are written for the .Net platform, one can achieve basically the same in Java using PowerMock and even (to some extent) in C++ using MockitNow.