Override Java System.currentTimeMillis for testing time sensitive code

Mike Clark picture Mike Clark · Jan 4, 2010 · Viewed 90.5k times · Source

Is there a way, either in code or with JVM arguments, to override the current time, as presented via System.currentTimeMillis, other than manually changing the system clock on the host machine?

A little background:

We have a system that runs a number of accounting jobs that revolve much of their logic around the current date (ie 1st of the month, 1st of the year, etc)

Unfortunately, a lot of the legacy code calls functions such as new Date() or Calendar.getInstance(), both of which eventually call down to System.currentTimeMillis.

For testing purposes, right now, we are stuck with manually updating the system clock to manipulate what time and date the code thinks that the test is being run.

So my question is:

Is there a way to override what is returned by System.currentTimeMillis? For example, to tell the JVM to automatically add or subtract some offset before returning from that method?

Thanks in advance!

Answer

Jon Skeet picture Jon Skeet · Jan 4, 2010

I strongly recommend that instead of messing with the system clock, you bite the bullet and refactor that legacy code to use a replaceable clock. Ideally that should be done with dependency injection, but even if you used a replaceable singleton you would gain testability.

This could almost be automated with search and replace for the singleton version:

  • Replace Calendar.getInstance() with Clock.getInstance().getCalendarInstance().
  • Replace new Date() with Clock.getInstance().newDate()
  • Replace System.currentTimeMillis() with Clock.getInstance().currentTimeMillis()

(etc as required)

Once you've taken that first step, you can replace the singleton with DI a bit at a time.