Unit Testing – How to Test Time-Bound Code

object-orientedtimetime-trackingunit testing

I'm currently working on an application that does a lot of time-bound operations. That is, based on long now = System.currentTimeMillis();, and combined with an scheduler, it will calculate periods of time that parametrize the execution of some operations. e.g.:

public void execute(...) { // executed by an scheduler each x minutes
    final int now = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
    final int alignedTime = now - now % getFrequency() ;
    final int startTime = alignedTime - 2 * getFrequency(); 
    final int endTimeSecs = alignedTime - getFrequency(); 
    uploadData(target, startTime, endTimeSecs);
}

Most parts of the application are unit-tested independently of time (in this case, uploadData has a natural unit test), but I was wondering about best practices for testing time-bound parts that rely on System.currentTimeMillis() ?

Best Answer

You should DEFINITELY arrange to mock-out the system clock. I've worked in C++, and either I make the object take a 'clock interface' object, or I use an internal interface or function pointer inside the class that I then replace when doing test code.

I've actually had experience with NOT mocking out the system clock and believe me when I tell you - it never ends well.

There are actually several problems with doing unit tests that rely on the real system clock. The first is that it's simply hard to do (you end up grabbing the clock, then doing stuff, then grabbing the clock again to verify), but it's also annoying because your test times become limited by real-time (if you are testing something that's 30 seconds, then it's 30+ seconds to run the test).

The most important problem, though, is that it makes your tests VERY BRITTLE.

Your tests will start to fail randomly due to server loading issues. They'll fail randomly, and you'll send time checking the failures over and over.

It's not worth it - use an interface for the system clock and mock it out in the test code.