Overview

Programs often need to capture the current system time. This is most often done by calling

System.currentTimeMillis()

or

new Date()

The problem with this approach is that logic using these calls is not easiy unit testable. The values created are different with each call. Thus it is not possible to declare fixed expected values.

The solution is to use WallClock instead to get the time value. By default it will return the current system time. Unit test logic can replace that behavior with a dummy clock that returns a fixed time.

The above calls should be replaced with:

WallClock.currentTimeMillis()

or

WallClock.currentDate()

In normal execution, the WallClock calls behave exactly as the system calls. The power of the framework is seen in unit test logic.

Example

Consider the following logic which captures current time.

public class ShortTimer {
    private final long fStart;

    public ShortTimer() {
        fStart = WallClock.currentTimeMillis();
    }

    public boolean isWithin100Ms() {
        return (WallClock.currentTimeMillis() - fStart) <= 100;
    }
}

Creating a unit test for this is made much easier by allowing manual time setting. This is done with the following unit test logic:

    @Test
    public void testShortTimer() {
        WallClock.Manual clock = WallClock.createManual();
        clock.setTimeMillis(700L);
        ShortTimer shortTimer = new ShortTimer();

        // Run no time off the clock.  We are within 100ms of the start.
        Assert.assertTrue(shortTimer.isWithin100Ms());

        // Run 50ms off the clock.  We are still within 100ms of the start.
        clock.setTimeMillis(750L);
        Assert.assertTrue(shortTimer.isWithin100Ms());

        // Run another 25ms off the clock.  We are still within 100ms of the start.
        clock.setTimeMillis(775L);
        Assert.assertTrue(shortTimer.isWithin100Ms());

        // Run another 50ms off the clock.  We are no longer within 100ms of the start.
        clock.setTimeMillis(825L);
        Assert.assertFalse(shortTimer.isWithin100Ms());

        // Run -75ms off the clock (go back in time).  We are back within 100ms of the start.
        clock.setTimeMillis(750L);
        Assert.assertTrue(shortTimer.isWithin100Ms());
    }

The first line replaces the underlying system clock with a manually set one. After that, all time values read are the values that are explicitly set.

For completeness, it is a good idea to reset to the system clock after the test is done:

    @AfterClass
    public static void clear() {
        WallClock.restoreSystem();
    }

Project Overview