How do I mock a private static final field initialized via a private constructor using Powermock and Mockito?

seeker picture seeker · Sep 10, 2016 · Viewed 7.7k times · Source

Here's my source class -

public class ClassToTest extends AbstractSuperClass<Integer> {
    private static final ClassToTest INSTANCE = new ClassToTest(); // (line 1) need to mock this variable

    static ClassToTest get() {
        return INSTANCE;
    }
    private ClassToTest() {
        super(Integer.class);// (line 2)
    }
}

Here's my attempt so far at testing it

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class TestClass {
    private ClassToTest testClass;
    @Before
    public void setUp() {
        // each of the below attempts fails at line 1  because of the call to line 2 (annotated above).
        // Attempt A.  
        testClass = WhiteBox.newInstance(ClassToTest.class);
        //Attempt B.
        testClass = mock(ClassToTest.class);
        WhiteBox.setInternalState(ClassToTest.class, "INSTANCE", testClass);
    }
    @Test
    public void dummy() {
        // irrelevant
    }
}

I'm trying to effectively mock out ClassToTest.INSTANCE and the call its private constructor. How could I do that?

EDIT : Snippet/Constructor invoked from AbstractSuperClass.

public abstract class AbstractSuperClass<V extends Serializable> {
    private final CacheClient<V> cache;
    private final int seconds;

    public AbstractSuperClass(Class<V> valueType) {
        cache = new ClientFactory(Config.getAppConfig(), StatisticSet.getGlobalStatistics()).newClient(getCacheType(), valueType);
        seconds = Config.getAppConfig().get(getCacheType().getSectionEnum()).getSeconds();
    }

P.S: I'm trying to stay away from dealing with the internals of AbstractSuperClass and had originally hoped to simply mock the call away. I'm also open to any ideas to refactoring ClassToTest to avoid this .

Answer

GhostCat picture GhostCat · Sep 11, 2016

Your real problem is that you created hard, almost un-testable code by making use of static. And not only that: you also create a bad design. Because you tightly couple your production classes to each other. Once in place, it will be hard to get rid of that static method later on.

So, the other option: instead of trying to "fix" a broken design by using PowerMock, you step back. You learn what "writing testable" code is actually about (for example by watching these videos); and then you use pure interfaces and dependency injection to solve your problem. And you test all of that with EasyMock or Mockito, without the need to Powermock!