PowerMockito -- Mock and Spy

A bad system design can lead to much hard work. In order to increase the unit tests coverage, I recently started to work on writing unit tests for some classes. One of the case is I want to test a method as follow:

1
2
3
4
5
6
7
8
public final ReturnType getMethod (SomeRequest someRequest) {
AnotherRequest anotherRequest = new AnotherRequest(someRequest);
SomeResponse someResponse = SomeService.getInstance().someMethod(anotherRequest);
SomeValue someValue = someResponse.getValue();
/**
* Some processes with someValue..
*/
}

The main purpose of this test is testing the process with someValue, so I should just mock the .getValue() method. But the thing is not that easy. Let me put more related classes here:
SomeService.class

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class SomeService {
private static SomeService instance = new SomeService();
static {
// A static block
}
protected SomeService() {}
public static SomeService getInstance() {
return instance;
}
public SomeResponse someMethod(AnotherRequest anotherRequest) {
// Implementation of the method..
}
}

SomeResponse.class

1
2
3
4
5
public class SomeResponse {
public SomeValue getValue() {
// Implementation of getValue()
}
}

SomeValue.class

1
2
3
4
5
6
7
8
9
public class SomeValue {
private String name;
private void populateValue(PreDefinedType preDefinedType) {
// Generate name from a preDefinedType, basically a black box.
}
public String getName() {
return name;
}
}

If I put the unit test as follow, I will get the java.lang.reflect.InvocationTargetException Error.

1
2
3
4
5
6
@RunWith(PowerMockRunner.class)
@PrepareForTest({SomeService.class, SomeResponse.class, SomeValue.class, SomeRequest.class})
public class ElasticSearchBasedTokenGeneratorServiceTest extends PowerMockTestCase {
// Mock every class and call..
// Find out more on https://github.com/jayway/powermock/wiki/MockitoUsage
}

It seems that mock library does not always work. A better way to do it is to create a Utilities.class to reset final static fields.

1
2
3
4
5
6
7
8
9
10
public class Utilities {
public static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
// remove final modifier from field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}

And then in the unit test, do the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@RunWith(PowerMockRunner.class)
@PrepareForTest({SomeService.class, SomeResponse.class, SomeValue.class, SomeRequest.class})
public class SomeTest extends PowerMockTestCase {
public void testMethod() throws Exception {
// Mock the request
SomeRequest someRequest = PowerMockito.mock(SomeRequest.class);
Mockito.when(entitiesRequest.method()).thenReturn("some thing");

// Mock response and its related value
SomeResponse someResponse = PowerMockito.mock(SomeResponse.class);
SomeValue someValue = PowerMockito.mock(SomeValue.class);
Mockito.when(someValue.getName()).thenReturn("some name");
Mockito.when(someResponse.getValue()).thenReturn(someValue);

// Mock the service
SomeService someService = PowerMockito.mock(SomeService.class);
Mockito.when(someService.someMethod(Mockito.any())).thenReturn(someResponse);

// To initialize the service, use the reflect method created above
Utilities.setFinalStatic(SomeService.class.getDeclaredField("someService"), someService);
SomeService someService = new SomeService();
someService.someMethod(someRequest);
// Assertion..
}
}

One thing I should mention is, in the actual SomeService.class, we should change the initialization of service outside the method (as a field):

1
private static final SomeService someService = SomeService.getInstance();
26 Memory Leak in Docker Container

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×