Mocking time in Java 8's java.time API
The closest thing is the Clock
object. You can create a Clock object using any time you want (or from the System current time). All date.time objects have overloaded now
methods that take a clock object instead for the current time. So you can use dependency injection to inject a Clock with a specific time:
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
See Clock JavaDoc for more details
I used a new class to hide the Clock.fixed
creation and simplify the tests:
public class TimeMachine {
private static Clock clock = Clock.systemDefaultZone();
private static ZoneId zoneId = ZoneId.systemDefault();
public static LocalDateTime now() {
return LocalDateTime.now(getClock());
}
public static void useFixedClockAt(LocalDateTime date){
clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);
}
public static void useSystemDefaultZoneClock(){
clock = Clock.systemDefaultZone();
}
private static Clock getClock() {
return clock ;
}
}
public class MyClass {
public void doSomethingWithTime() {
LocalDateTime now = TimeMachine.now();
...
}
}
@Test
public void test() {
LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2);
MyClass myClass = new MyClass();
TimeMachine.useFixedClockAt(twoWeeksAgo);
myClass.doSomethingWithTime();
TimeMachine.useSystemDefaultZoneClock();
myClass.doSomethingWithTime();
...
}
I used a field
private Clock clock;
and then
LocalDate.now(clock);
in my production code. Then I used Mockito in my unit tests to mock the Clock using Clock.fixed():
@Mock
private Clock clock;
private Clock fixedClock;
Mocking:
fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
doReturn(fixedClock.instant()).when(clock).instant();
doReturn(fixedClock.getZone()).when(clock).getZone();
Assertion:
assertThat(expectedLocalDateTime, is(LocalDate.now(fixedClock)));