1 year ago

#356998

test-img

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

Accepted video resources