StaticTimeRule.java
package uk.org.lidalia.test;
import org.joda.time.DateTimeUtils;
import org.joda.time.Instant;
import org.joda.time.ReadableInstant;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* A <a href="https://github.com/junit-team/junit/wiki">JUnit</a> rule that sets the time returned by the
* <a href="http://joda-time.sourceforge.net/">Joda Time</a> classes to a static
* time for the duration of the test.
* <p>
* At the start of each test the time as viewed by Joda Time classes is frozen to the provided time. At the end of the test it
* is returned to the system time. This makes time based testing predictable.
*/
public class StaticTimeRule implements TestRule {
/**
* @return a static time rule which will freeze the time at the start of the unix epoch
*/
public static StaticTimeRule alwaysStartOfEpoch() {
final Instant startOfEpoch = new Instant(0L);
return always(startOfEpoch);
}
/**
* @return a static time rule which will freeze the time at the instant this method was invoked
*/
public static StaticTimeRule alwaysNow() {
final Instant now = new Instant();
return always(now);
}
/**
* @param instant the instant at which time will be frozen
* @return a static time rule which will freeze the time to the provided instant
*/
public static StaticTimeRule always(final ReadableInstant instant) {
return new StaticTimeRule(instant);
}
private final ReadableInstant instant;
private StaticTimeRule(final ReadableInstant instant) {
super();
this.instant = instant;
}
@Override
public Statement apply(final Statement base, final Description description) {
return new StaticTimeStatement(base, instant);
}
/**
* @return the instant at which time is frozen by this rule
*/
public ReadableInstant getInstant() {
return instant;
}
private static class StaticTimeStatement extends Statement {
private final Statement base;
private final ReadableInstant instant;
public StaticTimeStatement(final Statement base, final ReadableInstant instant) {
super();
this.base = base;
this.instant = instant;
}
@Override
public void evaluate() throws Throwable {
try {
DateTimeUtils.setCurrentMillisFixed(instant.getMillis());
base.evaluate();
} finally {
DateTimeUtils.setCurrentMillisSystem();
}
}
}
}