8

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() ?

Michael K
  • 15,539
  • 9
  • 61
  • 93
maasg
  • 550
  • 4
  • 14

3 Answers3

14

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.

Michael Kohne
  • 10,038
  • 1
  • 36
  • 45
  • 2
    +1 for adding the own experience part. Reading/sleeping/reading/comparing timestamps is hell indeed. – maasg Jul 09 '12 at 15:22
12

Instead of calling System.currentTimeMillis() directly, I would wrap that in your own class and inject it into your code dynamically. What this gives you is the ability to mock your wrapper object to return a fixed time in the context of tests. This means that your test code will never actually call System.currentTimeMillis(), but rather get a fixed time to work with that you can predict.

Oleksi
  • 11,874
  • 2
  • 53
  • 54
  • 2
    Note that Guava has the [`Ticker`](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Ticker.html) class for just this purpose. – Daniel Pryden Jul 09 '12 at 16:32
  • @DanielPryden Ticker will give you ns which are only meaningful relative to each other. I need the system clock for my operations. – maasg Jul 10 '12 at 06:56
6

Do not use System.currentTimeMillis(), but program everything using time against an interface returning time. During unit-testing, mock the interface, else you simply cannot test anything using time reliably. This also has the benefit that if you decide currentTimeMillis is not accurate enough, you can replace it with another method in one single spot and everything will now use that other method.

stijn
  • 4,108
  • 1
  • 25
  • 31