Unit Testing Singletons

The Singleton

I would say that I fall into the camp that generally shies away from the use of singletons.  To start, singletons are a form of global state that is to be avoided.  They carry state across the entire execution of the program making both testing and debugging difficult.  It becomes hard to execute tests in isolation because they may modify the state of the singleton in ways that undesirably ties tests to a strict execution order.  Beyond problems with global state, objects that use singletons are highly coupled to the both the way the singleton is instantiated and the way it is implemented.  It isn’t possible to test an object that depends on a singleton without testing (or in someway relying on the behavior of) the singleton as well.   Furthermore, this coupling is hidden from the user of the object.  To correctly interact with the class depending on the singleton, a dependency that is not explicit in its interface, you must often also understand the behavior of the singleton.  In other words, the state and behavior of the singleton can affect the behavior of the depending object as well as transitive side effects.

This post wasn’t meant to be an analysis of the singleton pattern so I won’t go into additional details.  You can easily do a Google search for more information on this debate.  But the background is provided to frame why you need to use some different techniques for testing singletons. The take away point should be that if you find yourself creating a singleton, take a step back and reconsider your design and only use the singleton as a last resort.  Even if you really want only a single instance of a particular class, it is preferable for a dependency injection container or a factory object handle that requirement rather than the object itself.

Testing Singletons

Now that I’ve told you to avoid singletons if you can, I’m going to also say that you probably will at some point find a reason to implement one.  Or it may be the case that you are maintaining some legacy code or third party libraries that use them.  In that case, you are going to want to test them. To start the discussion, here is one of your standard singleton implementations in Java.

public class MySingleton{
 
   private static MySingleton instance;
 
   private MySingleton(){
 
        ...
 
   }
 
   public static synchronized MySingleton getInstance() {
      if (instance == null) {
         instance = new MySingleton();
      }
      return instance;
   }
 
   ...
 
}

The different ways of implementing singletons in Java have been discussed in great detail other places so I won’t discuss them here.  This IBM developerWorks article (with the updated information that it links to) is a good resource if you would like more background.

One scenario you may need to test is the instantiation of you singleton.  For example, your implementation may query some system properties to figure out how to initialize itself.  You may also want to test the standard instance methods.  Testing of neither of these scenarios is guaranteed to work consistently in a test case since the singleton carries its state throughout the life of the program.  You can’t guarantee a consistent starting state from test to test.  This is shown in the contrived example below.

    @Test
    public void somethingIsDoneWithAbcIsSetAsASystemProperty(){
        System.setProperty("com.example", "abc");
        MySingleton singleton = MySingleton.getInstance();
        assertThat(singleton.getSomething(), is("something"));
    }
 
    @Test
    public void somethingElseIsDoneWithXyzIsSetAsASystemProperty(){
        System.setProperty("com.example", "xyz");
        MySingleton singleton = MySingleton.getInstance();
        // This will fail because the single instance was already initalized with abc in the
        // previous test
        assertThat(singleton.getSomething(), is("something else"));
    }
 
    @Test
    public void whenTheSingletonIsStartedAndPauseIsInvokedTheStateIsChanged(){
        MySingleton singleton = MySingleton.getInstance();
        singleton.pause();
        assertThat(singleton.getState(), is("paused"));
    }
 
    @Test
    public void theNumberOfStateChangesIsTracked(){
        MySingleton singleton = MySingleton.getInstance();
        singleton.pause();
        singleton.start();
        singleton.stop();
        // This will fail because the previous test invoked a state change
        assertThat(singleton.getNumberOfTimesStateChanged(), is(3));
    }

By using reflection in one of your JUnit setup (i.e. @Before) methods, you can make sure each test starts with an uninitialized singleton and your tests are no longer affecting each other.

    @Before
    public void resetSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
       Field instance = MySingleton.class.getDeclaredField("instance");
       instance.setAccessible(true);
       instance.set(null, null);
    }

Now, the instance field is reset to null before each test case executes guaranteeing consistent state.

Testing Objects That Depend on Singletons

Consider the Customer class below. When you write tests that should be testing the logic around how you calculate the discount, you need to keep all the dependencies in a consistent state so that you can test your logic in isolation. The use of the singleton prohibits this.

public class Customer{
 
    public int caculateDiscount(){
        MySingleton singleton = MySingleton.getInstance();
        String something = singleton.getSomething();
        // do some calculations based on the value of something
        return ...;
    }
}

For testing objects that depend on singletons, you could also use the reflection approach above to better control the state of the singleton although it doesn’t help decouple your object under test from the singleton. The fact that you have to do this to test these objects clearly shows the coupling between the two objects. It should also be a bad testing smell that a Customer test has to fiddle with the internals of the MySingleton class when it isn’t even apparent through the interface that the MySingleton is a dependency.

public class CustomerTest {
 
    @Before
    public void resetMySingleton() throws SecurityException,
            NoSuchFieldException, IllegalArgumentException,
            IllegalAccessException {
        Field instance = MySingleton.class.getDeclaredField("instance");
        instance.setAccessible(true);
        instance.set(null, null);
    }
 
    @Test
    public void theDiscountShouldBe5PercentWhenSomethingOccurs(){
        // Test logic specific to the Customer
    }
}

Some Singleton Implementations Notes

To use the approach I’ve showed exactly the way I do above there are a couple very small requirements for the way you implement your singletons.  They shouldn’t be a problem though because you probably should be implementing them these ways (for correctness and safety) anyways.

The design restriction is that the field that you store you single instance in within your Singleton must not be final.  So the implementation shown above works fine.

And an alternative implementation where you instance isn’t lazily loaded is also fine if you make one small change to the reflection code (and you have a no-arg constructor).

public class MySingleton{
    private static MySingleton instance = new MySingleton();
 
   ...
 
}

The reflection code in your test would be:

   @After
    public void resetLog4jManagerSingleton() throws IllegalArgumentException,
            IllegalAccessException, InstantiationException, SecurityException,
            NoSuchFieldException, NoSuchMethodException,
            InvocationTargetException {
        Field instance = MySingleton.class.getDeclaredField("instance");
        instance.setAccessible(true);
 
        Constructor constructor = MySingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        instance.set(null, constructor.newInstance());
    }

But the following implementation won’t work and will result in a
java.lang.IllegalAccessException: Can not set static final com.example.MySingleton field com.example.MySingleton.instance to com.example.MySingleton

public class MySingleton{
   private static final MySingleton instance = new MySingleton();
 
   ...
 
}

Basically, you can’t modify a static final field with reflection (although you can modify a non-static final field in some versions of the JDK. See http://www.javaspecialists.eu/archive/Issue096.html for an in depth analysis if you are interested in this reflection stuff).

There are some other approaches for lazy initialization of singletons with supposedly better performance.  For example, the Initialization on Demand Holder (IODH) idiom.  I haven’t really thought it through or tried it since I haven’t used the idiom, but I think the reflection code could be modified to support this approach.


80 Responses to “Unit Testing Singletons”

Leave a Reply