要验证测试中的文件名,如何从 class 实例的方法调用的 System.currentTimeMillis() 中获取模拟值

To validate the file name from the test, how to to get mocked value from System.currentTimeMillis() that is called from a method of a class instance

我想模拟 System.currentTimeMillis() 方法到 return 从 MyClassImpl 实例构造函数调用 generateFileName 方法时的模拟值。

...
...

public class MyClassImpl {
    private String myFileName;

    public MyClassImpl() {
        generateFileName();
    }

    public String getMyFileName() {
        return myFileName;
    }

    private void generateFileName() {
        myFileName = "Request" + System.currentTimeMillis();
    }
}
...
...

@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
@PowerMockIgnore({"javax.management.*"})
public class MyClassImplTest {

    @Test
    public void testForFileSave() throws Exception {
        // Arrange
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.currentTimeMillis()).thenReturn(123456789L);

        System.out.println(System.currentTimeMillis() + " mocked current time");

        // Act
        MyClassImpl myclass = new MyClassImpl();

        // Assert
        assertThat(myclass.getMyFileName(), is("Request" + System.currentTimeMillis()));
    }
}

测试响应

123456789 mocked current time
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider jdk.nashorn.api.scripting.NashornScriptEngineFactory not a subtype
INFO 2021-03-05T07:45:32,390 org.eclipse.jetty.util.log [Test worker] Logging initialized @5103ms to org.eclipse.jetty.util.log.Slf4jLog


Expected: is "Request123456789"
     but: was "Request1614930331383"
Expected :Request123456789
Actual   :Request1614930331383

如何解决这个问题?

System.currentTimeMillis()放在单独的受保护方法中。在测试中创建一个测试 class 扩展 MyClassImpl 并覆盖受保护的方法,返回任何你想要的测试。

public class MyClassImpl {
    // ...

    private void generateFileName() {
        myFileName = "Request" + currentTimeMillis();
    }

    protected long currentTimeMillis() {
        return System.currentTimeMillis();
    }
}

public class MyClassMock extends MyClassImpl {
    @Override
    protected long currentTimeMillis() {
        return 123456789L;
    }
}

除了使用此自定义模拟 class,您还可以使用部分模拟(即 mockito 中的间谍)。