views:

193

answers:

3

How do you mock-up/trick the JVM to get a date other that the current system date? I have a set of tests in JUnit I don't want to change, but instead I want to change a setting so that when the JVM retrieves the date it retrieves the date I want.

Have you done something similar before?

Thanks.

+1  A: 

You could have a DateFactory interface with two implementations, one which always returns new Date() (this would be used in production), and a mock object which returns Date objects which are more appropriate for your unit tests.

(This is assuming you can change your code to make it more amenable to unit testing.)

Simon Nickerson
I doubt I could introduce a DateFactory in my case, but I'll analyze it.
Abel Morelos
A: 

I would rather try to hide that functionality behind a mockable interface, so that the "real" implementation gets the system date, while your mock implementation returns whatever date you have configured.

Messing with the system date in unit tests doesn't sound a very nice thing to me - I would try to avoid it if I can. Unit tests should be context-independent as much as possible - that saves a lot of trouble in the long run.

However, if you can't modify the code you are testing, you may have no other way. The question then is, are you interested only in the date, or the full timestamp? The latter case sounds pretty hopeless to me to achieve (in any other way than the above mock interface), as I guess simply resetting the date before running your tests is not enough - you need a fixed instant of time to be returned throughout your unit tests. Maybe your tests run fast enough to finish before the clock ticks, maybe not - maybe they pass right now, then start to fail randomly sometime later after adding the next test :-(

If you only need the date though, you might try changing the date in the @BeforeClass method, then resetting it in @AfterClass, although it is gross.

Péter Török
The interface idea sounds good, a change like this one may not conflict with some limitations I have to accept. I'll let you know later.
Abel Morelos
+2  A: 

There are a couple of ways to do this:

  • if you can rewrite code - as mentioned in some other answers, basically you need a configurable NowProvider, DateFactory, or other strategy (I like injectable NowProvider.now() as a dropin replacement for System.currentTimeMillis myself)

  • Powermock, and some other toolkits let you use ClassLoader tricks to override static methods, even system methods

jayshao
Powermock works great. Just used it to mock System.currentTimeMillis(). Thanks jayshao for the hint.
ReneS
Powermock? Mmm... seems like it's worth a try, if I can override System.currentTimeMillis while running my unit tests then this may be the answer, I'll let you know later about the outcome.
Abel Morelos
Thanks jayshao, Powermock provided me a very good option to handle this problem.
Abel Morelos
Glad it worked out for you - I'm a little uneasy about classloader manipulations in unit tests in principle, but there are a lot of cases where injecting data providers is just cruft IMHO.
jayshao