Skip to content
A small library for testing time-related stuff
Branch: master
Clone or download
Latest commit 3d8f1fb May 6, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
gradle/wrapper Add gradle wrapper Oct 23, 2018
src Make method public May 6, 2019
.gitignore add the build directory go .gitignore Nov 3, 2018
.travis.yml Update travis Nov 8, 2018
LICENSE Initial commit Oct 4, 2018
README.md Update README.md May 6, 2019
build.gradle Update version May 6, 2019
gradlew Add gradle wrapper Oct 23, 2018
gradlew.bat Add gradle wrapper Oct 23, 2018
settings.gradle Very first PoC version Oct 4, 2018

README.md

Maven Central Build Status codecov

haste

A small library for testing time-related stuff

Goals and motivation

In a few applications I was struggling with time aspect during tests. It's not hard to write some kind of proxy or mocks to provide a proper date but it is annoying to write them every time. Here comes the idea to create an open source library to help write tests based on the passage of time and also to help write more testable systems.

Usage

<dependency>
    <groupId>io.github.krasnoludkolo</groupId>
    <artifactId>haste</artifactId>
    <version>0.2.1</version>
</dependency>
compile 'io.github.krasnoludkolo:haste:0.2.1'

Features

TL;DR

Haste provides:

  • the implementation of ScheduledExecutorService with advanceTimeBy method to simulate lapse of time.
  • the interface TimeSource to create abstraction over time

Full version

Test scheduled tasks

Some actions in your system may also plan another actions to be done in the future. E.g. when you add a sport fixture you may want to check the result after it has finished When using normal java scheduler it is hard to test results of scheduled jobs without e.g. mocking. Here comes the implementation of ScheduledExecutorService with advanceTimeBy method.

class FooTest{
   
       private static final Runnable EMPTY_RUNNABLE = () -> {};
       private static final Callable<Integer> RETURN_ONE_CALLABLE = () -> 1;
   
       @Test
       void shouldExecuteAllScheduledJobs() throws ExecutionException, InterruptedException {
           BlockingScheduledExecutionService executorService = BlockingScheduledExecutionService.withFixedClockFromNow();
   
           ScheduledFuture<Integer> schedule1 = executorService.schedule(RETURN_ONE_CALLABLE, 1, TimeUnit.SECONDS);
           ScheduledFuture schedule2 = executorService.schedule(EMPTY_RUNNABLE, 2, TimeUnit.SECONDS);
           ScheduledFuture schedule3 = executorService.schedule(EMPTY_RUNNABLE, 3, TimeUnit.SECONDS);
           ScheduledFuture schedule4 = executorService.schedule(EMPTY_RUNNABLE, 5, TimeUnit.SECONDS);
   
           executorService.advanceTimeBy(4, TimeUnit.SECONDS);
   
           assertEquals(Integer.valueOf(1), schedule1.get()); //not null
           
           assertTrue(schedule1.isDone()); 
           assertTrue(schedule2.isDone());
           assertTrue(schedule3.isDone());
           
           assertFalse(schedule4.isDone());
       }

}
Get access to current time

With Haste comes the fallowing interface

public interface TimeSource {
    LocalDateTime now();
}
Standalone time source

If you only need access to current time, without whole ScheduledExecutionService staff, you can use MovableTimeSource with implements TimeSource interface. It simply works like in example

class MovableTimeSourceTest {


    @Test
    void shouldNowReturnTimeWithOffset() {
        Instant instant = Instant.ofEpochMilli(0);
        ZoneId zoneId = ZoneId.systemDefault();
        Clock clock = Clock.fixed(instant, zoneId);
        MovableTimeSource timeSource = Haste.TimeSource.withFixedClock(clock);

        timeSource.advanceTimeBy(1, TimeUnit.HOURS);

        LocalDateTime now = timeSource.now();

        LocalDateTime expected = LocalDateTime.now(clock).plusHours(1);
        assertEquals(expected, now);

    }

}
ScheduledExecutionService as time source

BlockingScheduledExecutionService from Haste implements that interface so you can obtain 'moved' time like in example

class Event{

    private LocalDateTime eventTime;
    private TimeSource timeSource;

    Event(LocalDateTime eventTime, TimeSource timeSource) {
        if (timeSource.now().isAfter(eventTime)) {
            throw new IllegalArgumentException("Cannot make event in past");
        }
        this.eventTime = eventTime;
        this.timeSource = timeSource;
    }

    boolean hasAlreadyBegun(){
        return timeSource.now().isAfter(eventTime);
    }

}
class EventTest {

    @Test
    void shouldEventStartsAfterStartDate() {
        BlockingScheduledExecutionService service = BlockingScheduledExecutionService.withFixedClockFromNow();
        LocalDateTime eventTime = LocalDateTime.now().plusHours(1);
        Event event = new Event(eventTime, service);
        
        service.advanceTimeBy(2, TimeUnit.HOURS);
        
        assertTrue(event.hasAlreadyBegun());
    }
}

Disclaimer

Keep in mind that Haste is in early-alpha phase which means that some API details may change between versions.

You can’t perform that action at this time.