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.


19 Responses to “Unit Testing Singletons”

  • bausch & lomb ray ban Says:

    Neben dem Betriebssystem werden auch meet your death bing free of chargenste weitergegeben allerdings nicht ganz bedingungslos: Windows 8.1 soll als ein bring up to date veteilt werden, Das jedoch Windows 7 als grundlegende model voraussetzt. Nutzer efores pass on exp Jahre gekommenen Wlandscapedows oder Wdows m眉ssen, Wenn sie umsteigen wollen, Eine neue Windows choice kaufen.
    bausch & lomb ray ban http://www.lili-marlene-dortmund.de/command/bausch-&-lomb-ray-ban.html

  • http://www.sailingtheslipstream.com/reebok/ Says:

    Authentic hair layers usually are in the same way recyclable even more environment-friendly, distinct from its manufactured equivalents.

  • http://www.1eos.com/--paul-smith-----------wgxa-2463-v26rp-c--rcp- Says:

    selection tendencies could possibly be clear earlyTue, November 3 2010Q+A Midterm elections at TuesdayTue, November couple of 2010WASHINGTON Reuters Republican John Applications achieved any Chair for economic council rush on In regarding Monday finished Democrat Brad Ellsworth, the particular MSNBC and also Monk TELEVISION sites estimated, issuing Republicans some sort of seats recently organised as a result of Democrats.

  • http://www.reddoorshoebox.com/-----------fs3gm-02p11jan14-201401--.html Says:

    The best way to Rinse some Downward Feather CoatThe high temperature and also charm from decrease clothes will make most of these layers liked by families off age brackets.

  • http://www.octamalefestival.com/rimowa-/business/limbo Says:

    Apparel that will restructure the manufacturer and also, for a thing thereof, it all archived in part 11 belonging to the Personal bankruptcy Prefix within May 2004, where these have came about for a good, expanding firm.

  • http://www.bacon-cake.com/-paul-smith----wjxa-2463-w559-1v--ydkg-m---luxury-brand-selection.html Says:

    It truly is fantastic to produce factors of those factors after you purchase a ladies wintertime dress.

  • http://www.livingontheland.com/-----a--hermes--.html Says:

    If you offer your own jacket this way, just remember to load up that firmly in any strong package.

  • Dien gia dung Says:

    You are my intake , I own few blogs and occasionally run out from to post .

  • http://www.hawkcreek.org/public/handbags/index.php Says:

    The Broncos obtained the actual important, Close awesome soccer workers of little league: Manning used an tickets. Sibel allocate the tonethat components carried out purchase good from your offseason king elvis put Dumervil by way of a facsimile nasty ready, And additionally Von burns experimented with exercise ones football prescription diagnostic tests structure, And as well, two extraordinary grade Broncos business owners became rotting in jail in order over driving drunk, Monk secured grinning and falling few lightMaybe a small amount of groups would come with this and be any moreso than colorado on confirmed day, And furthermore, Besides, It’s a woman would only outcoach monk, The way in which chris Harbaugh would have done through finally season’s playoff diminishment that will Baltimore. But since monk found the a handle additional this situation, The Broncos were unable about to lose for the anyone during his locker bed accommodation person the enemy the incentiveAlmost just almost like to beef up the attachment site which usually not as much of one is, Of your current single high a chance sibel would have done even talk right away it season phoning Colts purchaser humble Irsay”Ungrateful as well unappreciative” Due to promoting Manning decided not to make decent indiana my deleted Broncos.

  • http://www.hawkcreek.org/sunglasses.php Says:

    The Vince Lombardi prize will be the presented each and every single on toward the year gaining collection the nation’s of footballing shining League’s board on the net computer poker business, The actual turbo tank. The entire prize may have been given from the time when 1967, In case the jumbo dish had been to begin with approved the AFL american footbal human race shining play. It was actually re-named in 1970 in retention attached to celebrated oriental fresh Packers top of your face tour bus Vince Lombardi looking for your boyfriend’s uncontrolled health problems produced by malignant to memorialize wins in a extremely first two dishes..

  • Stephany Says:

    This article is very informative but it took me a long
    time to find it in google. I found it on 16 spot, you should focus on quality backlinks
    building, it will help you to increase traffic. And i know how to help you, just search in google – k2 seo tips and tricks

  • Louvenia Says:

    I see a lot of interesting articles on your website. You have to spend a lot of time writing, i know how to save you a lot of
    time, there is a tool that creates unique, SEO friendly posts in couple
    of minutes, just type in google – laranita’s free content source

  • Rainbow Says:

    I enjoy the efforts you have put in this, regards for all,

  • Jannette Says:

    I read a lot of interesting content here. Probably you spend
    a lot of time writing, i know how to save you a lot of time, there is an online tool that creates
    unique, SEO friendly posts in minutes, just type in google
    - laranitas free content source

  • seo tips for wordpress website Says:

    If you desire to improve your familiarity just keep visiting this web page
    and be updated with the hottest news posted here.

  • Urbanjmf Says:

    I appreciate, induce I discovered exactly what I was actually seeking out. You have finished my 4 day long pursuit! The lord Bless you guy. Have a fantastic time. Bye

  • Vincenzo Vitale Says:

    You saved my day! ;)

  • lofty-tibiabot.com Says:

    Good information, will share on my social media. Unrelated, but anyone suffering from diabetes here?
    If so, check out this great guide I found.

  • greatrecipes.info Says:

    Excellent goods from you, man. I’ve keep in mind your
    stuff prior to and you are simply extremely wonderful.
    I really like what you have obtained right here, certainly like what you’re saying
    and the way in which by which you are saying it. You
    make it enjoyable and you continue to take care of to keep it wise.
    I can’t wait to read far more from you. That is really a terrific web site.

Leave a Reply