JMockit 模拟 System.currentTimeMillis()

JMockit mocking System.currentTimeMillis()

运行本次测试:

@Test
public void testSystemCurrentTimeMillis() {
    new NonStrictExpectations(System.class) {{
        System.currentTimeMillis(); result = 1438357206679L;
    }};
    long currentTime = System.currentTimeMillis();
    assertEquals(1438357206679L, currentTime);
}

我得到一个 IllegalStateException:

java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter
    at unittests.DateTest.(DateTest.java:24)
    at unittests.DateTest.testSystemCurrentTimeMillis(DateTest.java:23)

我的测试 (JMockit 1.18) 有什么问题?

就像 JMockit 的许多事情一样,它很容易做到。试试这个..

@Test
public void testSystemCurrentTimeMillis(@Mocked final System unused) {
    new NonStrictExpectations() {{
        System.currentTimeMillis(); result = 1438357206679L;
    }};
    long currentTime = System.currentTimeMillis();
    assertEquals(1438357206679L, currentTime);
}

发现 this 网站是一个很好的参考,顺便说一下。可能您被静态方法绊倒了。您需要做的就是使用静态方法将 class 声明为 mocked——您永远不需要引用该变量,因此我将其命名为 "unused".

这个东西在 JMockit 1.17 版中引入只是为了在你的 NonStrictExpectation(){} 块中使用对象引用,Mocked 的弃用属性值

Deprecated the "value" attribute of @Mocked, which is used for "static" partial mocking. Existing uses should be replaced with "dynamic" partial mocking, by passing the instance or class to partially mock in a call to the Expectations(Object...) constructor, or by applying a MockUp class.

请参考以下link: JMockit version history

我的最终解决方案是为 System 创建一个 MockUp,它只模拟方法 currentTimeMillis():

private static class SystemMock extends MockUp<System> {
    @Mock
    public static long currentTimeMillis() {
        return 10000000L;
    }
}

@Test
public void testAddNowDate() {
    new SystemMock();
    long currentTime = System.currentTimeMillis();
    assertEquals(10000000L, currentTime);
}

是的,这是部分嘲讽。通过在 nonStrictExpectation(){} 中进行小的修正,您上面提到的代码也可以得到修复:

@Mocked
private System system;

new NonStrictExpectations() {{
    System.currentTimeMillis(); 
    result = 1438357206679L;
}};

long currentTime = System.currentTimeMillis();
assertEquals(1438357206679L, currentTime);

这应该也可以。

我为此使用 PowerMock:

private void configureSystemClockMock(final int clockJump) {
    AtomicInteger callCount = new AtomicInteger();

    Answer<Integer> answer = invocation -> {
        callCount.addAndGet(1);
        return callCount.get() * clockJump;
    };

    PowerMockito.mockStatic(System.class);
    PowerMockito.doAnswer(answer).when(System.class);
    System.currentTimeMillis();
}

当然你可以在调用中放任何你想放的东西。