1 year ago
#356998

Matt
Mocking a service that utilizes a static initializer
Given the following classes, I would like to test the first one. Where I'm running into trouble is that because these are used in AWS Lambda, services are architected a certain way for performance reasons (e.g. container reuse) and I'm finding it impossible to even get an empty test class to run thanks to the static initializer.
public class ClassToTest {
private static ServiceA serviceA = new ServiceA();
public boolean methodToTest() {
return serviceA.someMethod();
}
}
public class ServiceA {
public ServiceA() {
this(new ServiceB());
}
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
this.someVariable = serviceB.getExpensiveServiceData();
}
}
public class ServiceB{
private static final ExpensiveService expensiveService;
private static final Map<String, Object> expensiveServiceData;
static {
expensiveService = new ExpensiveService();
expensiveServiceData = expensiveService.getData();
}
public getExpensiveServiceData() {
return expensiveServiceData.get("...");
}
}
We use Mockito for our tests. I have added PowerMockito and set up my test as follows:
@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor({"com.x.ServiceA", "com.x.ServiceB"})
@PrepareForTest({ServiceA.class, ServiceB.class})
public class ClassToTestTest {
@InjectMocks private ClassToTest classToTest;
@Mock // All the classes...
public void methodToTestTest() {
// Doesn't even get here
classToTest.methodToTest();
}
}
This fails due to a NPE in getExpensiveServiceData()
because I'm ignoring the static initializer and thus the Map never gets created. And I can't use Whitebox.setInternal
to set the value programmatically because the class fails initialization before I have access to that. I assume ServiceA
shouldn't actually be calling the real implementation of ServiceB
but I don't know how to inject a mock into a mock like that in my test.
java
junit
mockito
powermockito
0 Answers
Your Answer