如何使用Powermock和Mockito模拟通过私有构造函数初始化的私有静态final字段?

时间:2016-09-10 17:51:55

标签: java unit-testing mockito powermock white-box

这是我的源类 -

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)
    }
}

这是我到目前为止测试它的尝试

@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
    }
}

我正在尝试有效地模拟ClassToTest.INSTANCE并调用其私有构造函数。我怎么能这样做?

编辑:从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:我正试图远离处理AbstractSuperClass的内部问题而原本希望简单地嘲笑这个电话。我也愿意重构ClassToTest以避免这种情况。

3 个答案:

答案 0 :(得分:1)

我不相信嘲笑这个领域是正确的方法,我甚至不相信有可能做到这一点你不能覆盖一个领域只有方法可以被覆盖,这实际上是嘲笑的工作方式。实际上,模拟只是我们覆盖方法的某种代理。

你应该模仿ClassToTest.get()而不是下一个:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class TestClass {
    private ClassToTest testClass;
    @Before
    public void setUp() {
        testClass = PowerMockito.mock(ClassToTest.class);
        PowerMockito.mockStatic(ClassToTest.class);
        Mockito.when(ClassToTest.get()).thenReturn(testClass);
    }

    @Test
    public void dummy() {
        // Here I get the instance of ClassToTest that I mocked in the setUp method
        System.out.println(ClassToTest.get());
    }
}

答案 1 :(得分:1)

您的真正的问题是,您使用静态创建了难以测试的硬编码。不仅如此:您还创建了一个糟糕的设计。因为您将生产类紧密地耦合在一起。一旦到位,稍后将删除该静态方法 hard

所以,另一个选择:你不再试图通过使用PowerMock来“修复”破碎的设计,而是退后一步。您将了解“编写可测试”代码的实际内容(例如,通过观察这些videos);然后使用纯接口和依赖注入来解决您的问题。你用EasyMock或Mockito测试所有这些,而不需要Powermock!

答案 2 :(得分:1)

我不明白你想要达到的目标,但这是在这里工作:

@PrepareForTest(ClassToTest.class) // required
@RunWith(PowerMockRunner.class)    // required
public class ClassToTestTest {

    private ClassToTest testClass;

    @Before
    public void setUp() throws Exception {
        this.testClass = Mockito.mock(ClassToTest.class);
        final Field instance = ClassToTest.class.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        instance.set(null, this.testClass);
    }

    @Test
    public void testGet() throws Exception {
        assertSame(this.testClass, ClassToTest.get());
        System.out.println(this.testClass);
    }
}

输出:

Mock for ClassToTest, hashCode: 1083021083

(使用powermock-api-mockito版本1.6.2测试)