How to instantiate a Singleton multiple times?
Asked Answered
T

9

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?

Tetragram answered 17/6, 2010 at 18:53 Comment(6)
Um.. the name sort of indicates that there must be only one single instance. If it cannot be tested as such, I suggest there might be a flaw in the design of the class.Sanitary
Wouldn't instantiating a Singleton twice be a test failure? This is a well-defined wrong behavior for a singleton...Larondalarosa
This is one of many reasons Singletons should be avoided like the plague.Scary
sry did a rollback by accidentTetragram
Exactly why would your test need to instantiate a second singleton?Barden
to simulate the same object which would be sent over from another device.Tetragram
M
9

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();
    }
}
Muro answered 17/6, 2010 at 19:7 Comment(4)
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.Gatlin
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.Muro
I think it's much better to just fix the code rather than hacking around it with reflection.Flashboard
why am I getting " java.lang.NoSuchMethodException" with java6? has this been patched?Bursar
M
18

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.

Masque answered 17/6, 2010 at 18:58 Comment(0)
P
17

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

Pastiche answered 17/6, 2010 at 18:55 Comment(2)
yes that's why I used it. But i thought that somehow one can do it.Endo
@Sebi - then test with it. Or use a mock to test without it, but don't try to make it something it is not.Pastiche
M
9

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();
    }
}
Muro answered 17/6, 2010 at 19:7 Comment(4)
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.Gatlin
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.Muro
I think it's much better to just fix the code rather than hacking around it with reflection.Flashboard
why am I getting " java.lang.NoSuchMethodException" with java6? has this been patched?Bursar
R
6

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.

Ramey answered 17/6, 2010 at 19:2 Comment(2)
Or, conversely, that the test itself is circumspect.Barden
In such case it might be helpful to create resetInstance method which remove private instance inside the class - this will help to test such casesFlambeau
J
3

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.

Junitajunius answered 17/6, 2010 at 19:18 Comment(0)
S
3

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?

Stockinet answered 17/6, 2010 at 19:33 Comment(0)
R
2

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; }
}
Retreat answered 17/6, 2010 at 18:56 Comment(2)
hmm yes but then I would have to change the code. If possible i want to avoid this.Endo
Guess this is a good way to wreck your code. On the plus side, your later unit tests will fire exceptions much more often :-)Tensity
P
0

Singleton ston=Singleton.getInstance(); will return singleton object. By making use of "ston" object, if we call the method createNewSingleTonInstance() which is written in Singleton class will give new instance.

public class Singleton {

private String userName;
private String Password;
private static Singleton firstInstance=null;
private Singleton(){}


public static synchronized Singleton getInstance(){
    if(firstInstance==null){
        firstInstance=new Singleton();
        firstInstance.setUserName("Prathap");
        firstInstance.setPassword("Mandya");
    }
    return firstInstance;
}


public void setUserName(String userName) {
    this.userName = userName;
}
public String getUserName() {
    return userName;
}
public void setPassword(String password) {
    Password = password;
}
public String getPassword() {
    return Password;
}

public Singleton createNewSingleTonInstance(){
    Singleton s=new Singleton();
    s.setUserName("ASDF");
    s.setPassword("QWER");
    return s;
}
}
Plus answered 3/6, 2014 at 11:42 Comment(0)
T
0

You may keep a key on a map and populate instance with key

public class MultiSingleton {
/**** Non-static Global Variables ***/
String status = "";
private BaseSmartCard bsc;
/***********************************/
private static Object lockObject = new Object();
private String serialNo;

private static Map<String, MultiSingleton> mappedObjects = new TreeMap<String, MultiSingleton>();

protected MultiSingleton() {

}


public static MultiSingleton getInstance(String serialNo,long slotNo){
    if (mappedObjects.isEmpty() || !mappedObjects.containsKey(serialNo)) {
        MultiSingleton instance = new MultiSingleton();
        instance.setSerialNo(serialNo);
        mappedObjects.put(serialNo, instance);
        return instance;
    } else if (mappedObjects.containsKey(serialNo)) {
        return mappedObjects.get(serialNo);
    }else {
        return null;
    }
}
Thalweg answered 17/3, 2016 at 23:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.