JMockit:模拟的 api 会在一段时间后恢复
JMockit: Mocked apis are getting reverted after sometime
我正在使用 JMockit 模拟 System.currentMillis()。
很少有调用返回模拟时间,但一段时间后,它开始返回原始时间。
当我禁用 JIT 后 运行 相同时,它 运行 完全没问题。
您显然对一个或多个组件中的当前时间有重要的依赖性。在这种情况下,您应该使用接口表达这种依赖关系:
public interface TimeService {
long currentTimeMillis();
}
在您的实际代码中,您有一个使用 System
方法的实现:
public final SystemTimeService implements TimeService {
@Override
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}
注意,使用 Java 8 可以减少一些代码以更清楚地表达它(感谢@Holger):
public interface TimeService {
static final DEFAULT = System::currentTimeMillis;
long currentTimeMillis();
}
您依赖于此时间服务的 类 应该如下所示:
public final ClassThatDependsOnTimeService {
private final TimeService timeService;
public ClassThatDependsOnTimeService(TimeService timeService) {
this.timeService = timeService;
}
// other features omitted
}
现在可以用
喂它们了
TimeService timeService = new SystemTimeService();
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(timeService);
或 (Java 8):
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(TimeService.DEFAULT);
或任何依赖注入框架或其他任何东西。
在你的测试中你不模拟方法 System.currentTimeMillis
但你模拟接口 TimeService
并将模拟注入到依赖 类.
发生这种情况是因为 JVM 中的 JIT 优化器不检查重新定义的方法(重新定义是通过 JVM 中的不同子系统完成的)。因此,最终 JVM 决定优化包含对 System.currentTimeMillis()
的调用的代码,内联对 native
Java 方法的调用,以便它直接开始执行实际的本机方法。此时,优化器应该检查 currentTimeMillis()
当前是否被重新定义,并在被重新定义的情况下放弃内联。但是,不幸的是,JDK 工程师未能考虑到这种可能性。
如果你真的需要多次调用模拟的 System.currentTimeMillis()
,唯一的解决方法确实是 运行 和 -Xint
(这不是一个坏主意,因为它通常会减少测试的总执行时间 运行).
我正在使用 JMockit 模拟 System.currentMillis()。
很少有调用返回模拟时间,但一段时间后,它开始返回原始时间。
当我禁用 JIT 后 运行 相同时,它 运行 完全没问题。
您显然对一个或多个组件中的当前时间有重要的依赖性。在这种情况下,您应该使用接口表达这种依赖关系:
public interface TimeService {
long currentTimeMillis();
}
在您的实际代码中,您有一个使用 System
方法的实现:
public final SystemTimeService implements TimeService {
@Override
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}
注意,使用 Java 8 可以减少一些代码以更清楚地表达它(感谢@Holger):
public interface TimeService {
static final DEFAULT = System::currentTimeMillis;
long currentTimeMillis();
}
您依赖于此时间服务的 类 应该如下所示:
public final ClassThatDependsOnTimeService {
private final TimeService timeService;
public ClassThatDependsOnTimeService(TimeService timeService) {
this.timeService = timeService;
}
// other features omitted
}
现在可以用
喂它们了TimeService timeService = new SystemTimeService();
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(timeService);
或 (Java 8):
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(TimeService.DEFAULT);
或任何依赖注入框架或其他任何东西。
在你的测试中你不模拟方法 System.currentTimeMillis
但你模拟接口 TimeService
并将模拟注入到依赖 类.
发生这种情况是因为 JVM 中的 JIT 优化器不检查重新定义的方法(重新定义是通过 JVM 中的不同子系统完成的)。因此,最终 JVM 决定优化包含对 System.currentTimeMillis()
的调用的代码,内联对 native
Java 方法的调用,以便它直接开始执行实际的本机方法。此时,优化器应该检查 currentTimeMillis()
当前是否被重新定义,并在被重新定义的情况下放弃内联。但是,不幸的是,JDK 工程师未能考虑到这种可能性。
如果你真的需要多次调用模拟的 System.currentTimeMillis()
,唯一的解决方法确实是 运行 和 -Xint
(这不是一个坏主意,因为它通常会减少测试的总执行时间 运行).