出于某些测试目的,我想准确预测System.currentTimeMillis()
将返回什么。有什么办法可以冻结或手动设置调用System.currentTimeMillis()
时会返回什么内容?
答案 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() - 请参阅其他答案。