Setting time and date in JUnit test fixture

2019-01-24 17:12发布

问题:

As part of Java code some task needs to be done tomorrow in JUnit.

For example there are 3 tasks:

  • task1 - done
  • task2 - do it tomorrow
  • task3 - then this will happen

So as per requirement I need to set today's date as tomorrow in Java.

回答1:

The root of your problem is that the system clock (what gives you the time in a new Date ()) is not giving you the time you need for your test.

You can avoid this problem by introducing a level of indirection. Instead of having your code directly ask the Java API what the current time is, you have your code ask a Clock object what the time is. In the real program your Clock implementation uses the system clock. For your unit tests you use a FakeClock, which says whatever time you want it to. You tell your code what Clock to use using dependency injection. You have to write the Clock interface (or abstract base class) and its concrete implementations yourself.

This approach requires you to alter your existing code, so it is easier to test, or write it in the first place so it is easier to test. It's one of the tricks of unit testing.

I'm working on some code at the moment that is time sensitive. My clock interface is simply

 public interface Clock {
    long getCurrentTime ();
 }


回答2:

The key is to extract the idea of "something which can give you the current time" as a dependency. (Along with the relevant time zone.)

So instead of using new Date() or System.currentTimeMillis() you use a Clock abstraction. For production code you inject an instance of this which uses the underlying system clock, but for testing you use a fake clock which you can control explicitly, to make it return whatever you want to.

(It's really not clear exactly what you're trying to achieve, to be honest - but this approach is my standard approach to making time testable.)



回答3:

Consider the following code on GitHub: DateSupplier && DateController. DateSupplier has a static method that returns the current date. DateController allow you to manipulate the date value that is returned by DateSupplier in a test environment. It is a JUnit Rule and cleans up after itself.

This is a concrete implementation of the Clock ideas from the other two answers. I have been using it in my projects for a year or so with good success. Any time I have code that would do new Date() I call DateSupplier.getCurrentDate() instead.



回答4:

Consider using Joda Time, which is a replacement for Java's date and time classes. It provides

DateTimeUtils.setCurrentMillisFixed(long millis);

which can be used in your tests.



标签: java junit