nocandies nocandies - 4 months ago 16
Java Question

Can not make the mocked singleton's method behave differently in different test cases

The unit test of a class is involved with a static method in a another class, say

HelperClass
.
HelperClass
has a singleton member. I used
Junit
for the unit tests and
Powermockito
to mock the singleton member. But I found that the behavior of the method of the singleton member can only be specified once.

//the class to be tested
class Activity {
public void enact() {
//some logic
String str = HelperClass.doSomething();
//some other logic
}
}

class HelperClass {
private static final singleton = Singleton.getInstance();
public static String doSomething() {
//some logic
AnObject obj;
try {
obj = singleton.doSomething();
} catch (Exception1 e) {
//Some other logic
throw new Exception2("Some message" + e.getMessage(), e);
}

String val = obj.doSomething();
return val;
}
}

class Singleton {
private Singleton instance = null;
private void Singleton() { /*some logic*/ }
public static Singleton getInstance() {
if (instance == null) {
Singleton();
}
return instance;
}
public String doSomething() throws Exception1 {
//some logic
}
}


My uint test goes like this

@RunWith(PowerMockRunner.class)
@PrepareForTest(Singleton.class)
class ActivityTest {
//some logic
private Activity activity;

@Before
public void setup() {
//some logic
PowerMockito.mockStatic(Singleton.class);
activity = new Activity();
}

@Test(expected = Exception2.class)
void test1() {
Singleton mockSingleton = mock(Singleton.class);
when(mockSingleton.doSomething()).thenThrow(new Exception1("Test Exception1"));
PowerMockito.when(Singleton.getInstance()).thenReturn(mockSingleton);

activity.enact();
}

@Test
void test2() {
Singleton mockSingleton = mock(Singleton.class);
when(mockSingleton.doSomething()).thenReturn("");
PowerMockito.when(Singleton.getInstance()).thenReturn(mockSingleton);

activity.enact();
}
}


But it does not work. Although I specify different behaviors of the
doSomething()
of the
mockSingleton
, the
mockSingleton
still throws the
Exception2
in
test2
as it does in
test1
. It seems that the behavior can only be specified once. Can somebody tell me how I can let the
doSomething()
here have different behaviors?

Answer

You are calling Signleton.getInstance only once - when HelperClass is initialized. This way you always use the mock from your first test. To solve this, you can call getInstance every time you need an instance of Singleton.

Thus, the code for HelperClass would be:

class HelperClass {
    public static String doSomething() {
       //some logic
       AnObject obj;
       try {
           obj = Singleton.getInstance().doSomething();
       } catch (Exception1 e) {
           //Some other logic
           throw new Exception2("Some message" + e.getMessage(), e);
       }

       String val = obj.doSomething();
       return val;
    }
}

This way, you will get the right mock on every run.

Comments