Unit testing a class with a Java 8 Clock

Create a Mutable Clock Instead of Mocking

To start, definitely inject a Clock into your class under test, as recommended by @Jon Skeet. If your class only requires one time, then simply pass in a Clock.fixed(...) value. However, if your class behaves differently across time e.g. it does something at time A, and then does something else at time B, then note that the clocks created by Java are immutable, and thus cannot be changed by the test to return time A at one time, and then time B at another.

Mocking, as per the accepted answer, is one option, but does tightly couple the test to the implementation. For example, as one commenter points out, what if the class under test calls LocalDateTime.now(clock) or clock.millis() instead of clock.instant()?

An alternate approach that is a bit more explicit, easier to understand, and may be more robust than a mock, is to create a real implementation of Clock that is mutable, so that the test can inject it and modify it as necessary. This is not difficult to implement, or here are several ready-made implementations:

  • https://github.com/Mercateo/test-clock (this one is published on Maven Central HT: @Bartek Jablonski)
  • https://github.com/ThreeTen/threeten-extra/blob/master/src/main/java/org/threeten/extra/MutableClock.java (also on Maven Central HT: @Wim Deblauwe)
  • https://github.com/robfletcher/test-clock

And here is how one might use something like this in a test:

MutableClock c = new MutableClock(Instant.EPOCH, ZoneId.systemDefault());
ClassUnderTest classUnderTest = new ClassUnderTest(c);

classUnderTest.doSomething()
assertTrue(...)

c.instant(Instant.EPOCH.plusSeconds(60))

classUnderTest.doSomething()
assertTrue(...)

I don't want to add a Clock argument to the method because the real code shouldn't be concerned with passing in a clock.

No... but you might want to consider it as a constructor parameter. Basically you're saying that your class needs a clock with which to work... so that's a dependency. Treat it as you would any other dependency, and inject it either in a constructor or via a method. (I personally favour constructor injection, but YMMV.)

As soon as you stop thinking of it as something you can easily construct yourself, and start thinking of it as "just another dependency" then you can use familiar techniques. (I'm assuming you're comfortable with dependency injection in general, admittedly.)


I'm a bit late to the game here, but to add to the other answers suggesting using a Clock - this definitely works, and by using Mockito's doAnswer you can create a Clock which you can dynamically adjust as your tests progress.

Assume this class, which has been modified to take a Clock in the constructor, and reference the clock on Instant.now(clock) calls.

public class TimePrinter() {
    private final Clock clock; // init in constructor

    // ...

    public void printTheTime() {
        System.out.println(Instant.now(clock));
    }
}

Then, in your test setup:

private Instant currentTime;
private TimePrinter timePrinter;

public void setup() {
   currentTime = Instant.EPOCH; // or Instant.now() or whatever

   // create a mock clock which returns currentTime
   final Clock clock = mock(Clock.class);
   when(clock.instant()).doAnswer((invocation) -> currentTime);

   timePrinter = new TimePrinter(clock);
}

Later in your test:

@Test
public void myTest() {
    myObjectUnderTest.printTheTime(); // 1970-01-01T00:00:00Z

    // go forward in time a year
    currentTime = currentTime.plus(1, ChronoUnit.YEARS);

    myObjectUnderTest.printTheTime(); // 1971-01-01T00:00:00Z
}

You're telling Mockito to always run a function which returns the current value of currentTime whenever instant() is called. Instant.now(clock) will call clock.instant(). Now you can fast-forward, rewind, and generally time travel better than a DeLorean.


Let me put Jon Skeet's answer and the comments into code:

class under test:

public class Foo {
    private final Clock clock;
    public Foo(Clock clock) {
        this.clock = clock;
    }

    public void someMethod() {
        Instant now = clock.instant();   // this is changed to make test easier
        System.out.println(now);   // Do something with 'now'
    }
}

unit test:

public class FooTest() {

    private Foo foo;
    private Clock mock;

    @Before
    public void setUp() {
        mock = mock(Clock.class);
        foo = new Foo(mock);
    }

    @Test
    public void ensureDifferentValuesWhenMockIsCalled() {
        Instant first = Instant.now();                  // e.g. 12:00:00
        Instant second = first.plusSeconds(1);          // 12:00:01
        Instant thirdAndAfter = second.plusSeconds(1);  // 12:00:02

        when(mock.instant()).thenReturn(first, second, thirdAndAfter);

        foo.someMethod();   // string of first
        foo.someMethod();   // string of second
        foo.someMethod();   // string of thirdAndAfter 
        foo.someMethod();   // string of thirdAndAfter 
    }
}