是否可以冻结System.currentTimeMillis()进行测试

时间:2013-07-01 06:04:00

标签: java testing

出于某些测试目的,我想准确预测System.currentTimeMillis()将返回什么。有什么办法可以冻结或手动设置调用System.currentTimeMillis()时会返回什么内容?

6 个答案:

答案 0 :(得分:23)

我强烈建议您避免在通用代码中使用System.currentTimeMillis(以及new Date()等)。

相反,创建一个Clock接口,表示“为您提供当前时间的服务”,然后创建一个 使用System.currentTimeMillis或其他什么的实现,以及假的您可以明确控制的实现。

使用依赖注入使该服务的实例可用于需要它的代码。在制作中,使用System.currentTimeMillis版本,并在测试中使用您的假。

这使您不仅能够停止时间,而且能够将其设置为您想要的任何内容 - 因此您可以获得您知道永远不会过期的静态测试数据,并且您可以轻松地测试边界附近的棘手事物等等。我在很多项目中非常成功地使用了这种方法,在我的Noda Time项目中,它是 获取“当前时间”的方式。

请注意,如果您在Java中花费了大量时间,我建议您使用Joda Time,并使Clock界面返回Instant

public interface Clock {
    Instant now();
}

答案 1 :(得分:18)

是的,这是可能的,但这是测试代码的味道。

您可以使用模拟库来模拟静态方法(如此PowerMock example),但您应该避免这样做,并将时间数据封装为其他答案所示。

这是测试的样子,使用 PowerMock Mockito

@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
public class TestTime {

    @Test
    public void testTime() {
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.currentTimeMillis()).thenReturn(42l);
        System.out.println(System.currentTimeMillis()); //prints 42

        //your test code here
    }

}

答案 2 :(得分:1)

是否可以冻结System.currentTimeMillis()?

如果您希望能够对代码进行测试,则需要使用一种围绕该时间值的包装

答案 3 :(得分:1)

不,你不能设置或冻结System.currentTimeMills()。 但是如果你的需求是这样的,那么在这种情况下,你可以在变量中设置时间并在需要时使用。但System.currentTimeMills()将始终以毫秒为单位返回当前时间值。

答案 4 :(得分:1)

Java 8中内置的新java.time包包含一个java.time.Clock接口,“允许在需要时插入备用时钟。请改用它。

答案 5 :(得分:-2)

是的,解决方案存在:

出于测试目的,您可以创建自己的包装器系统,例如

package my.pack;

import java.io.PrintStream;

public class System
{
    // reuse standard System.out:
    public static PrintStream out = java.lang.System.out;

    // do anything with chosen method
    public static long currentTimeMillis()
    {
        return 1234567;
    }

}

并将其导入您要测试的课程

import my.pack.System;

在这种情况下,对System的所有调用都将通过您自己的System类传递。

注意:

  • 这是“如何拦截System.currentTimeMillis()”的解决方案

  • 这是 NOT 适合自动测试

  • 这是 NOT “如何设计优秀程序”的一个例子。如果您要求一个好的设计,那么您需要重构代码,替换System.currentTimeMillis() - 请参阅其他答案。