Sunday, August 22, 2004

In my previous Singleton Unit Testing, I proposed a possible solution for unit testing a singleton (I'll name it the ShortLivingSingleton approach). Omer Van Kloeten came up with another approach (the KillTheSingleton approach), Darren Oakey with the CreateForTesting approach and , Len Holgate finishes the picture tearing appart our the first 2 solutions (the SingletonIsBad approach). Since comments on this topic have been interresting, they are worth a little summary.

The problem

The application you are developping is using a Singleton, that you need to test. How do you test a singleton ?

SingletonIsBad approach

  1. Singleton are evil! If you have the opportunity to refactory the code, make sure you definitely need this singleton, otherwize get rid of it.
  2. You have no choice and you cannot get rid of the singleton. Make sure you split the singleton functionalities in two classes: The class that does all the work and the singleton aspect that prevents multiple instances. Doing so, you will not have to cheat to test the singleton.
  3. You could not fullfill any of the point above, and you will need to cheat...

The two first point came from Len Holgate and I totally agree with him. The third point is for tester who do not have the possiblity of avoiding or refactoring the singleton. To tackle this problem, I and Omer have proposed 2 cheats and Darrel Oakley proposed a wider solution to the problem.

CreateForTesting approach

The approach asks you to embed some functionality in a class that helps other people test it. The most common thing is to add - to most objects - a function CreateTestFoo, where Foo is the object that you are testing. This gives you a new and fully initialized version of Foo - however complicated Fooactually is.

Cheating the singleton.

Both cheat solutions are based on Reflection, therefore they will not work if you have denied Reflection on your tested assembly (Haacked's  comment).

ShortLivingSingleton  approach

This approach consists of creating a new non-singleton approach for each test and do the testing on this instance. To do so, we use reflection to access the private constructor and instanciate the singleton. Therefore, the singleton is never created and never used.

KillTheSingleton approach

This approach kills the singleton after each test, in the TearDown method for example. To "kill" the singleton, the static field holding the singleton reference is nullified using Reflection and garbage collection is forced.

Conclusions

Singletons are evil but yet you find people using them (shame on me). They are problematic to test because you cannot separate the unit tests.  The first step for testing them is actually to refactor your application and get rid of the singleton. If this cannot be done, you have to cheat the singleton using Reflection to properly test them.

ps: I'd like to thank all the people who commented the blog entry for their constructive comments :) Cheers, Jonathan

posted on Monday, August 23, 2004 1:06:00 AM UTC  #    Comments [6]
Tracked by:
"sacred heart tattoo" (online) [Trackback]
"japanese millet" (online) [Trackback]
Monday, June 06, 2005 5:37:42 PM UTC
Actually I believe that Singleton's can be very useful. I personally haven't seen anybody overusing it yet - mostly because I haven't seen anybody using it at all :)
<br>From my point of view a &quot;useful&quot; Singleton should not maintain state - or should not let change its state from external users/classes. This makes it again possible to test a Singleton by its regular GetInstance() (or whatever) method.
Eduard Liebenberger
Monday, June 06, 2005 5:37:43 PM UTC
&gt;From my point of view a &quot;useful&quot; Singleton should not maintain state - or should not let change its state from external users/classes.
<br>
<br>Then you don't need a singleton, a static class with static methods is sufficient.
Jonathan de Halleux
Monday, June 06, 2005 5:37:43 PM UTC
Ok, now I feel bad for using Singleton. Congratulations.
<br>
<br>Can I ask how you, as a designer, would represent a piece of custom hardware to an application.
<br>
<br>Would you have seperate instances. Every piece of code can just create an instance of the class that talks to the hardware? Or do you use a singleton, which is the only instance, which means something like writing and reading to the device can be controlled using queues and such.
<br>
<br>I'm just curious. I have two singletons in my application. They are both the representations of custom pieces of hardware which the application needs to talk to. It felt like Singleton was the perfect pattern for this, but you say Singleton should never/rarely be used.
<br>
<br>My singletons maintain state. They keep a record of whether the device is currently reading/writing/idle etc. However only the singleton controls what state it is in. No outside code can make it change state, only listen for events when it actually changes state
<br>
<br>So I'm curious. In what situations SHOULD it be used?
Sean Malloy
Monday, June 06, 2005 5:37:44 PM UTC
Sean,
<br>
<br>&gt;Every piece of code can just create an instance of the class that talks to the hardware?
<br>
<br>Indeed that's just non-sense, and I had not though about software that drives hardware but you are definitely pointing a situation I had not considered. From my point of view, Singleton seems to be the right choice in your case.
<br>
<br>I think that Singleton who represent &quot;software&quot; resource like we considered can always be refactored and avoided. The picture changes when you start dealing with &quot;hardware&quot; resource which a natural singleton... and they cannot be refactored and avoided: you can refactor hardware resource!
<br>
<br>Software writers who do not deal with hardware have a different view of the world than those who deal with it...
<br>
<br>You should also ask this question to Len Holgate or even post a &quot;Singleton is Bad... but not Always&quot; post on your blog :)
<br>
<br>
Jonathan de Halleux
Monday, June 06, 2005 5:37:44 PM UTC
You got me all doubting my decision to of applying Singleton.
<br>
<br>Unit testing a singleton which represents a piece of hardware is hard anyway. Theres no real way to automatically test a device which requires a human to interact with it to test it =\ (Inserting/removing cassettes, inserting tickets for validation etc)
<br>
<br>I feel better about my choice now
<br>
<br>
Sean Malloy
Monday, June 06, 2005 5:37:44 PM UTC
C#deSamurai
Comments are closed.