Overview
Over the years, there has been a bustling debate among software developers on the use of the singleton pattern. Some would say it is better in the sense that it has complete control of the object instantiation and ensures that there is one and only one instance of the class, but others feel that it is an anti-pattern since the instantiation part should not be the responsibility of the class itself. We could arm wrestle on each of these individual points all day and not come up with something more conclusive, but in this article I would like to put the questions “How do we unit test a singleton object?” and “How do we make singleton classes unit testable?” as the green and red cherry spots in the dart board.
Let’s get started with testing a singleton class that is dependent on another singleton class.
public
class
DependentObject
{
private
static
readonly
Lazy<DependentObject> _instance =
new
Lazy<DependentObject>(() =>
DependentObject());
DependentObject Instance {
get
return
_instance.Value; } }
DependentObject()
Initialize();
}
string
GetSampleObjectFullName()
SampleSingleton.Instance.GetFullName();
void
Initialize()
//do initialization processes
sealed
SampleSingleton : BaseObject
Lazy<SampleSingleton> _instance =
Lazy<SampleSingleton>(() =>
SampleSingleton());
SampleSingleton Instance {
SampleSingleton()
ID = 0;
FirstName =
"John"
;
LastName =
"Doe"
GetFullName()
.Concat(FirstName,
" "
, LastName);
ChangeFirstName(
newName)
FirstName = newName;
Now, let’s go ahead and test the DependentObject class.
[TestMethod]
Test_GetFullName()
name =
"John Doe"
Assert.AreEqual(name,DependentObject.Instance.GetSampleObjectFullName());
A mediocre can say this is good enough as a unit test as we can verify here if the method inside the class returns the expected result. Some people might agree with this but the bigger question here is “Are we really unit testing” in this particular case? If you refer back to the main goal of unit testing, it says we want to isolate each component or class as an independent unit and prove that the individual parts that make it as a whole are all working correctly.
In the above example, can we say that we have satisfied the main goal for unit testing? Have we isolated the class as an independent unit? Can we prove that it only performs what is expected from it? In order to answer these questions, we need to rip open the frog and see what is inside and then analyze how each of the parts is working with each other. Yes, it doesn’t sound like fun but most of the time I say you have to be a man and do the right thing.
So we have two singleton classes, DependentObject and SampleSingleton. The DependentObject contains a method GetSampleObjectFullName which in turn uses the SampleSingleton instance to invoke its GetFullName method and return the value. From the unit testing perspective, we want to test the GetSampleObjectFullName method.
If you first look at the method, you would say its responsibility is to return the sample object’s fullname but it’s not. For me, its sole responsibility is to invoke the GetFullName method of the SampleSingleton instance and then return whatever the result is. If you can recall encapsulation and single responsibility principles, the DependentObject does not and should not have any visibility into how the invoked method is working internally nor if the returned value is correct or not. In our current code, we cannot isolate the two classes independently because they have strong coupling between each other. We have to re-design them in such a way that we can create true and efficient unit test methods. On the other hand, imagine re-engineering the frog and be able to alter the functions of its internal parts and replace it with whatever we come up with every time we finish our glass of dirty martini. J(Now you say, Oh!, this looks interesting now.)
To remove the hard-coded dependencies between classes, we will re-design our example to follow an interface based design and replace the interface dependencies with whatever we can think of later. The interfaces and classes will now look like the code shown below:
interface
ISampleImpl
GetFullName();
newName);
SampleSingleton : BaseObject, ISampleImpl
Lazy<ISampleImpl> _instance =
Lazy<ISampleImpl>(() =>
ISampleImpl Instance {
IDependentObject
GetSampleObjectFullName();
ISampleImpl SampleObject {
set
; }
DependentObject : IDependentObject
Lazy<IDependentObject> _instance =
Lazy<IDependentObject>(() =>
IDependentObject Instance {
SampleObject = SampleSingleton.Instance;
SampleObject.GetFullName();
ISampleImpl SampleObject
You will notice that not much of the actual implementation code has changed. We just modified the structure and have the classes inherit from a common interface so that we can independently isolate one another when we create the “true” unit test. In our example, we need to isolate the SampleSingleton class from the DependentObject class and we can do that by replacing the SampleObject property with a mocked object. This practice is called Dependency Injection. There are various forms of Dependency Injection(DI) and since we exposed a public property to inject a new implementation, this particular type is called Property Injection. I also mentioned that we are going to use a mocked object in our testing. For this example, we will utilize a mocking framework called Moq.
Test_That_GetSampleObjectFullName_Invokes_ISample_GetFullName()
var mockedSample =
Moq.Mock<ISampleImpl>();
IDependentObject obj2Test = DependentObject.Instance;
obj2Test.SampleObject = mockedSample.Object;
//use of property injection
mockedSample.Setup(x => x.GetFullName());
obj2Test.GetSampleObjectFullName();
mockedSample.VerifyAll();
If you will compare this from the first unit test example, your first reaction would be, “Does that mean I have to write more code”? Yes, you might end up writing more. It is because you need to isolate the class you are testing from other components that it is dependent with. In unit testing, that is the responsibility of the mocking framework. Going back to our objective, we only need to verify if the GetSampleObjectFullName method really invokes the GetFullName method of the ISampleImpl interface. The good news is that the mocking framework has the facility to setup those expectations within your unit test. In the example above, we first created the mocked object for the ISampleImpl interface. We then instantiated our object to be tested and that remains a singleton instance. The third line is the part where we replaced the SampleSingleton instance in the DependentObject with a mocked object. We then call the Setup method of the mocking framework to specify that we are expecting a method named “GetFullName” will be invoked by our method under testing. Finally, we concluded our test by checking if all of our expectations are met.
By executing the test, the result looks like this:
1 passed, 0 failed, 0 skipped, took 0.59 seconds (Ad hoc).
By modifying the code not to invoke the method,
//SampleObject.GetFullName();
The new test result looks like this:
Test 'M:Singleton.Test.TestDependentObject.Test_That_GetSampleObjectFullName_Invokes_ISample_GetFullName' failed: The following setups were not matched:
ISampleImpl x => x.GetFullName()
Moq.MockVerificationException: The following setups were not matched:
at Moq.Mock.VerifyAll()
TestDependentObject.cs(24,0): at Singleton.Test.TestDependentObject.Test_That_GetSampleObjectFullName_Invokes_ISample_GetFullName()
0 passed, 1 failed, 0 skipped, took 0.72 seconds (Ad hoc).
You might ask, why did I use property injection instead of constructor injection? Due to the nature of singletons which are sealed and doesn’t have publicly accessible constructor we cannot use the mocking framework and we will have no way of replacing the dependency object and isolate our target object.
I hope this article has helped you in some way in understanding the challenges with unit testing singleton objects, how to decouple your classes by following an interface based design to make them independent and testable and lastly how you would use mocking frameworks to implement the isolation and setup unit test expectations.
I am now trying to imagine how many external interfaces have you come up with your modern frog? I was thinking of exposing an interface on the legs so i can inject a mocked Leg and have it jump all the way to the top of John Hancock Tower here in Boston. J
Happy Unit Testing!
Mabuhay!
Maheshkumar S Tiwari edited Revision 1. Comment: Added tags