Reputation: 12601
I have an app that manages turns in a game, it's fairly complex and it has a lot of timers that generate timeouts.. since they interoperate a lot it's difficult to be sure everything's working right (and keeps working right).
I'd like to test it, but certain timeouts are of a few minutes, to test it completely it'd take at least one hour!!
Is there any way to fake an accelerated time for the timers? Or should I just scale all the timeouts proportionally down, test them, and scale them up again each time?
thanks!
Upvotes: 6
Views: 1771
Reputation: 22721
I was doing something along the same lines, but thinking about slowing down the JVM by messing with the internals of Hotspot. It's not that hard, but it can introduce subtle bugs if not done right. Anyway, I posted a question here asking something along those lines, and someone came up with the idea of running the virtual machine in VirtualBox, and slowing down the time (in my case, to gain extra CPU time). Perhaps you could speed up the time in your case, reducing CPU time, but making tests finish earlier. Or maybe there's a precision limit to the timer, or VirtualBox can only slow down time.. hmm.
Upvotes: 0
Reputation: 12601
I thought of a simple way.. not nice maybe but still.. I can do as aioobe said (the TIME_SCALING) put keep it private in the class, then access it from the tests using reflection.. this way at least it can't be seen or used by other classes..
Upvotes: 0
Reputation: 48196
relying on timer ticks to happen on the right time is prone to difficult to trace and rare bugs
I'd suggest using locks, barriers, semaphores, ect. to guarantee happens-before relations on everything; this requires more interaction between classes but is more bullet proof (and allows the program to run faster in testing with only one timer needed if it goes way too fast)
Upvotes: 1
Reputation: 17321
A way to do this would be to make your own interface that provides a thin wrapper around Timer
. You then program towards the interface everywhere in your code. After that, you make two implementations of the interface. The first is the expected implementation that connects to a real Timer
object like you have currently. The other is one that you can use for testing. In this implementation you mock the functionality of a Timer
, but you have full control of how the events are triggered and how long they take. You could scale the duration as suggested by @aioobe or you could make a backing queue that could rapidly fire events so that there is no wasted time.
The point is that you don't have to make changes to the real code and use Dependency Injection to make changes needed for testing.
Upvotes: 3
Reputation: 4443
Maybe you can just simulate the effects of a timer going off, and checking the state of the application based on that. It wouldn't help test the timers, but it would be a way to test their effects.
Upvotes: 0
Reputation: 421020
There is to my knowledge no way to do a global scaling of the speed of the Java Timers. (Assuming they rely on the System.currentTimeMillis
method, you could perhaps try to add your own bootclasspath and override this implementation with something different, but this is tricky business for sure (if it's even possible).)
I suggest you add a TIME_SCALING
factor in front of periods and frequencies used for debugging purposes.
// ...
long period = (long) (someValue / TIME_SCALING);
// ...
// ...
double frequency = someValue * TIME_SCALING;
// ...
Upvotes: 1