I have a Singleton class to test:
public class Singleton {
private static Singleton instance;
private List<String> list;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
public boolean methodOne() {
if (list == null) {
list = new ArrayList<String>();
list = SomeClass.fillListOne();
}
return SomeClass.verifyList(list);
}
public boolean methodTwo() {
if (list == null) {
list = new ArrayList<String>();
list = SomeClass.fillListTwo();
}
return SomeClass.verifyList(list);
}
}
With the following test class:
@RunWith(JMockit.class)
public class SingletonTest {
@Test
public void testOne(final @Mocked SomeClass someClass) {
Singleton.getInstance().methodOne();
new Verifications() {
{
SomeClass.fillListOne();
}
};
}
@Test
public void testTwo(final @Mocked SomeClass someClass) {
Singleton.getInstance().methodTwo();
new Verifications() {
{
SomeClass.fillListTwo();
}
};
}
}
If I execute only "testOne" or only "testTwo", the tests pass. If I execute all tests, it passes only the first method executed. How can I set "list" attribute to null, for instance in a @Before method? How to use Deencapsulation with Singleton or private member without setters?
That class is not particularly susceptible to testing. I'd urge you to rewrite it if you have the option to. (Testing with mocked static method calls is a maintenance nightmare, and I also have a general dislike of all things singleton-y -- they seem to be used everywhere whether they should be or not).
Regardless, the documentation suggests you could do something like this (I also added an extra field for readability, though you don't have to):
@RunWith(JMockit.class)
public class SingletonTest {
private Singleton instance;
@Before
public void initialise() {
Deencapsulation.setField(Singleton.class, "instance", null);
instance = Singleton.getInstance();
}
@Test
public void testOne(final @Mocked SomeClass someClass) {
instance.methodOne();
new Verifications() {
{
SomeClass.fillListOne();
}
};
}
// ...other tests...
}