JMockit: Erupted apis return after somtime
This is because the JIT optimizer in the JVM does not check for overridden methods (overriding is done through a different subsystem in the JVM). So ultimately the JVM decides to optimize the code containing the call in System.currentTimeMillis()
by inserting the call to the native
Java method so that it runs the actual native method directly. At this point, the optimizer must check whether it is overridden currentTimeMillis()
or not and discard the nesting if it is overridden. Unfortunately, the JDK engineers were unable to explain this possibility.
If you really need to call the mocked one too many times System.currentTimeMillis()
, the only workaround really should be done with -Xint
(which is not too bad since it usually reduces the overall test run time).
source to share
Obviously, you have an important current time dependency inside one or more of your components. In this case, you have to express this dependency using an interface:
public interface TimeService {
long currentTimeMillis();
}
In your real code, you have an implementation using the method System
:
public final SystemTimeService implements TimeService {
@Override
public long currentTimeMillis() {
return System.currentTimeMillis();
}
}
Please note, as of Java 8, you can shrink the code to express it more clearly (thanks @Holger):
public interface TimeService {
static final DEFAULT = System::currentTimeMillis;
long currentTimeMillis();
}
Your classes that depend on this time service should look like this:
public final ClassThatDependsOnTimeService {
private final TimeService timeService;
public ClassThatDependsOnTimeService(TimeService timeService) {
this.timeService = timeService;
}
// other features omitted
}
They can now be fed with
TimeService timeService = new SystemTimeService();
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(timeService);
or (Java 8):
ClassThatDependsOnTimeService someObject = new ClassThatDependsOnTimeService(TimeService.DEFAULT);
or with any dependency injection infrastructure, etc.
In your tests, you are not mocking the method System.currentTimeMillis
, but you are mocking the interface TimeService
and injecting the mock into the dependent classes.
source to share