Temporary Unit Tests

I need to check a function whose result will depend on the current time (using the Joda isBeforeNow() ).

  public boolean isAvailable() { return (this.someDate.isBeforeNow()); } 

Is it possible to mute / ridicule the system time using Mockito so that I can reliably check the function?

+70
java junit jodatime mockito
Apr 11 2018-11-11T00:
source share
5 answers

Joda time supports setting a “fake” current time using the setCurrentMillisFixed and setCurrentMillisOffset methods of the DateTimeUtils class.

See https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html.

+61
Apr 11 2018-11-11T00:
source share

The best way (IMO) to do your test code is to extract the dependency "what is the current time" in your own interface, with an implementation that uses the current system time (usually used) and an implementation that allows you to set the time, advance it as you want , etc.

I used this approach in different situations and it worked well. It is easy to set up - just create an interface (e.g. Clock ) that has one method to give you the current moment in whatever format you want (e.g. using Joda Time or possibly Date ).

+120
Apr 11 '11 at 13:45
source share

Java 8 introduced the abstract class java.time.Clock , which allows you to have an alternative implementation for testing. This is exactly what John suggested in his answer.

+18
Jul 16 '15 at 21:35
source share

To add Jon Skeet to the answer , Joda Time already contains the current time interface: DateTimeUtils.MillisProvider

For example:

 import org.joda.time.DateTime; import org.joda.time.DateTimeUtils.MillisProvider; public class Check { private final MillisProvider millisProvider; private final DateTime someDate; public Check(MillisProvider millisProvider, DateTime someDate) { this.millisProvider = millisProvider; this.someDate = someDate; } public boolean isAvailable() { long now = millisProvider.getMillis(); return (someDate.isBefore(now)); } } 

Change the time in the unit test (using Mockito , but you can implement your own MillisProviderMock class):

 DateTime fakeNow = new DateTime(2016, DateTimeConstants.MARCH, 28, 9, 10); MillisProvider mockMillisProvider = mock(MillisProvider.class); when(mockMillisProvider.getMillis()).thenReturn(fakeNow.getMillis()); Check check = new Check(mockMillisProvider, someDate); 

Use current production time ( DateTimeUtils.SYSTEM_MILLIS_PROVIDER was added to Joda Time in 2.9.3):

 Check check = new Check(DateTimeUtils.SYSTEM_MILLIS_PROVIDER, someDate); 
+4
Mar 28 '16 at 7:18
source share

I use an approach similar to Jon's, but instead of creating a specialized interface for the current time only (e.g. Clock ), I usually create a special test interface (say, MockupFactory ). I put there all the methods that I need to check the code. For example, in one of my projects, I have four methods:

  • one that returns the layout database client;
  • which creates a mock-up notifier object that notifies the code of changes to the database;
  • which creates the java.util.Timer layout, which runs tasks whenever I want;
  • which returns the current time.

The class under test has a constructor that takes this interface among other arguments. Anyone who does not have this argument simply creates a default instance of this interface that works "in real life." Both the interface and the constructor are closed to the package, so the testing API does not flow outside the package.

If I need more simulated objects, I just add a method to this interface and implement it in both test and real implementations.

Thus, I develop the code suitable for testing, first of all, without imposing too much on the code itself. In fact, the code becomes even cleaner as the factory code is assembled in one place. For example, if I need to switch to another database client implementation in real code, I need to change only one line, and not look around the constructor reference.

Of course, as in the case of John, he will not work with third-party code that you cannot or cannot change.

+1
Oct 23 '13 at 5:56 on
source share