Functions - A First Exercise

Mock a Clock

Mock a Clock

Functions are great for testability

  • Testing with time is difficult
  • Repeatability and predictability is limited
  • Looking for something that does not require mocking
  • Returns the real time
  • Returns a static time if needed
  • Returns a predefined series if required
/**
 * Time Service
 */
public interface TimeService
{
    /**
     * Returns the current in msec since 1970-01-01 in UTC
     *
     * @return current time in msec since 1970-01-01
     */
    public long currentTime();
}

A Mocked Clock

How a solution might look like

public class TimeService
{
    // hold our source
    private final LongSupplier source;
    
    /**
     * A standard system time based service
     */ 
    public TimeService()
    {
        this.source = System::currentTimeMillis;
    }

    /**
     * Inject any time of source that supplies longs
     * @param source a long supplier
     */ 
    public TimeService(final LongSupplier source)
    {
        this.source = source;
    }
    
    /**
     * Returns the time based on the chosen supplier
     * @return the time as long
     */ 
    public long currentTime()
    {
        return source.getAsLong();
    }
}
public class TimeMock
{
    @Test
    public void standardTime()
    {
        final TimeService ts = new TimeService();
        Assert.assertTrue(System.currentTimeMillis() >= ts.currentTime());
    }
    
    @Test
    public void staticTime()
    {
        final TimeService ts = new TimeService(() -> 412345678);
        Assert.assertTrue(412345678 == ts.currentTime());
    }
    
    @Test
    public void timeList()
    {
        final Deque<Long> series = new ArrayDeque<>();
        series.addAll(Arrays.asList(4L, 5L, 6L));
        
        final TimeService ts = new TimeService(series::pop);
        
        Assert.assertTrue(4 == ts.currentTime());
        Assert.assertTrue(5 == ts.currentTime());
        Assert.assertTrue(6 == ts.currentTime());
    }
}