tags:

views:

311

answers:

8

I need a singleton in my code. I implemented it in Java and it works well. The reason I did it, is to ensure that in a mulitple environment, there is only one instance of this class.

But now I want to test my Singleton object locally with a Unit test. For this reason I need to simulate another instance of this Singleton (the object that would be from another device). So is there a possiblity to instantiate a Singleton a second time for testing purpose or do I have to mock it?

I'm not sure, but I think it could be possible by using a different class loader?

+13  A: 

The point of a Singleton is that you can only instantiate it once.

Oded
yes that's why I used it. But i thought that somehow one can do it.
Roflcoptr
@Sebi - then test with it. Or use a mock to test without it, but don't try to make it something it is not.
Oded
Why the downvote?
Oded
wasn't me...(chars)
Roflcoptr
+1  A: 

you could just make another static method getInstance2 that looks like this:

class MySingleton
{
    private MySingleton(){}
    private static MySingleton instance1 = new MySingleton();
    private static MySingleton instance2 = new MySingleton();

    public static MySingleton getInstance(){ return instance1; }
    public static MySingleton getInstance2(){ return instance2; }
}
Joel
hmm yes but then I would have to change the code. If possible i want to avoid this.
Roflcoptr
Guess this is a good way to wreck your code. On the plus side, your later unit tests will fire exceptions much more often :-)
Eiko
+14  A: 

Traditionally, a Singleton creates its own instance, and it creates it only once. In this case it is not possible to create a second instance.

If you use Dependency Injection, you can let the framework create the singleton for you. The singleton does not guard against other instances (i.e. it has a public constructor), but the dependency injection framework instantiates only one instance. In this case, you can create more instances for testing, and your object is not cluttered with singleton code.

Sjoerd
+4  A: 

A singleton, by definition, can only be instantiated once. However, the fact that your unit test requires two singletons is a strong indication that your object shouldn't really be a singleton, and that you should rethink the singleton design.

JSBangs
Or, conversely, that the test itself is circumspect.
Chris Lively
+4  A: 

You can invoke the private constructor of your singleton class using reflection to create a new instance of the class.

class MySingleton {
    private MySingleton() {
    }
}

class Test {
    public void test() throws Exception {
        Constructor<MySingleton> constructor = MySingleton.class.getConstructor();
        constructor.setAccessible(true);
        MySingleton otherSingleton = constructor.newInstance();
    }
}
abhin4v
Sure, or you could just subclass MySingleton to expose the constructor. If you have existing code which invokes MySingleton.getInstance().blach(), this all that code will fail.
Justin
thanks that's what i'm looking for
Roflcoptr
This is for the purpose of testing a singleton class. I do not recommend doing this in non-test code. I think it is ok to use reflection to reach to otherwise unreachable methods for the purpose of testing.
abhin4v
yes. that's only for the purpose of testing. thanks.
Roflcoptr
I think it's much better to just fix the code rather than hacking around it with reflection.
Tom Hawtin - tackline
+1  A: 

I feel compelled to post this series of articles about how Singletons destroy testability and are poor design choices:

Short summary: combining logic for what a class does with how it is instantiated makes code that is ugly to test, and should be avoided.

matt b
+1  A: 

First, why do you need to create a new singleton to run a unit test? A unit test should not be running concurrently with the normal application, so you should be able to access the original singleton without fear of modifying it..

Is there a particular reason you need an explicit second singleton?

Stefan Valianu
A: 

Write your own classloader to load the class a second time, then create a new instance from that class.

ammoQ