Mocking the unmockable

Mocking the unmockable

Most of these are not recommendable practices. Powermock is being replaced by Mockito 2.0, and the reflection tricks should be avoided.
However we may happen to need them due to working with legacy code.

Let’s suppose we have taht kind of class with several issues such as this excerpt:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class CTProcessConfig implements ProcessEngineLookup {
private static final String TENANT = "TENANT";

// a private variable we can not modify as there is no setter
private String privateName = "DUMMY_SERVICE";

private Map<String, ProcessEngine> storage;
private static DataSource datasource;

public CTProcessConfig() {
storage = new HashMap<>();
initializeStorage();
}

// this is an static method
public static DataSource getDatasource() {
if (datasource == null) {
try {
// this is a constructor call, we can't mock it with Mockito
datasource = (DataSource) new InitialContext().lookup(
PROCESS_ENGINE_JNDI_SOURCE);
} catch (NamingException e) {
throw new IOException("Unable to construct the datasource", e);
}
}
return datasource;
}

//this is a private method which can't be tested on its own
@Override
private TransactionManager lookupTransactionManager() {
try {
// this is an static method call, we can't mock it with Mockito
return InitialContext
.doLookup(WEB_LOGIC_TRANSACTION_MANAGER_BEAN_NAME);
} catch (NamingException e) {
throw ClinicalTrialException
.create("Unable to lookup transaction manager", e);
}
}
}

PowerMock dependencies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${version.org.mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${version.powermock}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${version.powermock}</version>
<scope>test</scope>
</dependency>

How to mock the static

We have the InitialContext class. We should use Powermock in order to do that.

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
26
27
28
29
30
31
32
33
34
35
// use the powermock runner
// do not forget to add the problematic static class on prepare with
@RunWith(PowerMockRunner.class)
@PrepareForTest({ InitialContext.class })
public class CTProcessConfigTest {

// a private variable we can not modify
private String privateName = "DUMMY_SERVICE";

// instance to test
private CTProcessConfig instance;

// Mockito mocks
@Mock
private InitialContext initialContext;
@Mock
private TransactionManager transactionManager;
@Mock
private Datasource datasource;

@Before
public void setUp() throws NamingException {
initInitialContext();
// initialize your instance for tests
instance = new CTProcessMultiengineConfig();
}

private void initInitialContext() throws NamingException {
// mock the static
PowerMockito.mockStatic(InitialContext.class);
// treat it like a normal mockito mock
Mockito.when(InitialContext.doLookup(Matchers.anyString()))
.thenReturn(transactionManager);
}
}

How to test a private method

This is not a recommended, but there are cases when private methods are overwritten, so they are not easy to test individually. Let’s suppose we want to test the lookupTransactionManager method on its own. We can’t as it is private, hence we can use reflection to get it, make it accesible, and then set it back to its original state.

1
2
3
4
5
6
7
8
@Test
public void lookupTransactionManager_validResult(){
Method method = instance.getClass()
.getDeclaredMethod("lookupTransactionManager");
method.setAccessible(true);
Assert.asserEquals(transactionManager, method.invoke(instance));
method.setAccessible(false);
}

You may generalize the process in a similar way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static Object invokeMethodByName(Object instance, String nameOfMethod,
List<Class> parametersClass, List<Object> parametersValues)
throws InvocationTargetException {
Object result = null;
try {
Method method = instance.getClass().getDeclaredMethod(nameOfMethod,
parametersClass.toArray(new Class[]{}));
method.setAccessible(true);
result = method.invoke(instance, parametersValues.toArray());
method.setAccessible(false);
} catch (IllegalArgumentException | NoSuchMethodException |
IllegalAccessException | InvocationTargetException e) {
LOG.log(Level.SEVERE, null, e);
}
return result;
}

How to change the value of a private variable

Let’s suppose we need to modify an attribute value, but we have no setter available.

1
private String privateName = "DUMMY_SERVICE";

We may use reflection once again.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Before
public void setUp(){
Field field = instance.getClass().getDeclaredField("name");
setValueToPrivateField(instance, field, "NEW_NAME");
}

private void setValueToPrivateField(Object object, Field privateField,
Object newFieldValue) throws IllegalArgumentException, IllegalAccessException,
SecurityException {
privateField.setAccessible(true);
privateField.set(object, newFieldValue);
privateField.setAccessible(false);
}

How to mock a constructor call

Be careful as your coverage metter may not work as expected, but if you debug the code you will see it is working as expected, covering the code.

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
26
27
28
29
30
31
32
33
34
35
36
37
// use the Powermock runner
// add the problematic static class and the current class where the "new" happens
@RunWith(PowerMockRunner.class)
@PrepareForTest({ InitialContext.class, CTProcessConfig.class })
public class CTProcessConfigTest {

// instance to test
private CTProcessMultiengineConfig instance;

// Mockito mocks
@Mock
private InitialContext initialContext;
@Mock
private TransactionManager transactionManager;
@Mock
private Datasource datasource;

@Before
public void setUp() throws NamingException {
initInitialContext();
// initialize your instance for tests
instance = new CTProcessConfig();
}

private void initInitialContext() throws NamingException {
// mock the constructor, check the arguments
PowerMockito.whenNew(InitialContext.class).withNoArguments()
.thenReturn(initialContext);
// regular Mockito code
Mockito.when(lookUp(Matchers.anyString())).thenReturn(datasource);
}

@Test
public void getDatasource(){
Assert.assertEquals(datasource, instance.getDatasource());
}
}

How to mock a transaction lock on an EntityManager

Let’s suppose we have to test the following code, with JPA QueryDSL:

1
2
3
4
5
6
7
8
9
10
11
12
private EntityManager em;
private root;

@Override
public long unlockByLockedBy(@Nonnull final String lockedBy) {
final QUnionControlReport root = QUnionControlReport.unionControlReport;
return new JPAUpdateClause(entityManager, root)
.where(root.lockedBy.equalsIgnoreCase(lockedBy))
.setNull(root.lockedBy)
.setNull(root.lockDateTime)
.execute();
}

We need the transaction to get engaged, so we would only need to begin a transaction, and and not forget to finish it to avoid getting stuck.

1
2
3
4
5
6
7
8
9
/**
* Test unlockByLockedBy
*/
@Test
public void unlockByLockedBy() {
em.getTransaction().begin();
assertNotNull(instance.unlockByLockedBy("lockedBy"));
em.getTransaction().commit();
}