views:

304

answers:

6

I have a standalone singleton which successfully passes the test. But with a group of tests this fails since once a singleton is defined it does not allow to reset the instance.

Any ideas about how to go about this?

A: 

You can add a method to destroy the signleton, for example destryMe(); where you de-initialize everything and set the instance of the singleton to null.

public void destoryMe(){
   this.instance = null;
   //-- other stuff to turn it off.
}

I will leave synchronization problems though ;)

But why do you need to re-initialize your singleton for each test? It should not differ based on the concept of the singleton.

Regards.

Omar Al Kababji
A: 

I assume you have a private static field within your singleton class to store the initialized instance.

If you do not want to modify your code, you can define a teardown method which run after every test, and in this method you set this static field to null via reflection as seen here.

Csaba_H
-1, IMO this is making a bad situation worse
orip
+1  A: 

generally beware of singletons, most often they are evil, bad design and tend to represent big yucky global variables (which is bad for maintenance).

still to get tests in place first you can do:


static setInstance(...){ //package visibility or in difficult cases you have to use public
  instance = ...;
}

as said this is more a workaround. so get first tests place, but then refactor away from singleton pattern.

manuel aldana
A: 

Singleton instance needs to be passed to SUT by test itself - that way you create singleton (and destroy) for each test. Adopting IoC and mocking framework, like Mockito, would render this approach almost trivial.

grigory
+2  A: 

Don't use a singleton.

Specifically, the only difference between a singleton and a global variable is that the singleton tries to enforce a single instance (by making the constructor private, for example).

Instead, make the constructor public and write tests using new instances. In your actual program, use getInstance() to get the canonical global instance (or use an IOC container).

And remember that singletons are pathological liars.

If you're still too comfortable with the idea of a Singleton, instead of making the constructor public you can add a public (and static) factory method to create instances in a way that can't be used by accident, e.g.:

public static MyClass TEST_CreateInstance() {
  return new MyClass();
}
orip
+1  A: 

I highly recommend moving away from Singletons as a design pattern, and using Singleton as a scope (Dependency Injection). This would simply make your problem go away.

But assuming you are stuck in the world of Singletons, then you have a few options depending on if you are testing the Singleton or the dependency.

If you are testing the dependant item then you can mock the Singleton using PowerMock and JMockIt. See my previous post about mocking Runtime.getRuntime for instructions on how to go about this.

If you are testing the Singleton then you need to relax the rules on construction, or give the Singleton a "Reset" method.

mlk