有一个普遍的问题:很难模拟时间。此外,将长时间运行/等待的代码放在单元测试中是非常糟糕的做法。
因此,为了使调度 API 可测试,我使用了一个具有真实和模拟实现的接口,如下所示:
public interface Clock {
public long getCurrentMillis();
public void sleep(long millis) throws InterruptedException;
}
public static class SystemClock implements Clock {
@Override
public long getCurrentMillis() {
return System.currentTimeMillis();
}
@Override
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
}
public static class MockClock implements Clock {
private final AtomicLong currentTime = new AtomicLong(0);
public MockClock() {
this(System.currentTimeMillis());
}
public MockClock(long currentTime) {
this.currentTime.set(currentTime);
}
@Override
public long getCurrentMillis() {
return currentTime.addAndGet(5);
}
@Override
public void sleep(long millis) {
currentTime.addAndGet(millis);
}
}
有了这个,你可以在你的测试中模仿时间:
@Test
public void testExpiration() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExpiration("foo", 1000);
clock.sleep(2000) // wait for 2 seconds
assertNull(sco.getIfNotExpired("foo"));
}
当然,高级多线程模拟Clock
要复杂得多,但是您可以使用ThreadLocal
引用和良好的时间同步策略来实现它。