Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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

share|improve this question
    
those ints should be const :] –  stijn Jul 9 '12 at 14:44
    
@stijn const??? –  maasg Jul 9 '12 at 14:50
    
ah, sorry probably this is C#? Then forget about const, that's for C++ –  stijn Jul 9 '12 at 15:06
    
@stijn changed to follow your suggestion. Not that it would make much difference but at least you can deduce what language it is :-) –  maasg Jul 9 '12 at 15:18

3 Answers 3

up vote 10 down vote accepted

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.

share|improve this answer
2  
+1 for adding the own experience part. Reading/sleeping/reading/comparing timestamps is hell indeed. –  maasg Jul 9 '12 at 15:22

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.

share|improve this answer
2  
Note that Guava has the Ticker class for just this purpose. –  Daniel Pryden Jul 9 '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 6:56

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.