Có một vấn đề chung: thật khó để chế nhạo thời gian. Ngoài ra, thực sự không tốt khi đặt mã chạy / chờ lâu trong bài kiểm tra đơn vị.
Vì vậy, để làm cho một API lập lịch có thể kiểm tra được, tôi đã sử dụng một giao diện có triển khai thực và giả như thế này:
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);
}
}
Với điều này, bạn có thể bắt chước thời gian trong bài kiểm tra của mình:
@Test
public void testExipres() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
clock.sleep(2000) // WAIT FOR 2 SECONDS
assertNull(sco.getIfNotExpired("foo"));
}
Tất nhiên, một giả lập đa luồng nâng cao cho Clock
phức tạp hơn nhiều, nhưng bạn có thể tạo ra nó với các ThreadLocal
tham chiếu và một chiến lược đồng bộ hóa thời gian tốt, chẳng hạn.
Thread.sleep
nói điều gì đó như Sử dụng Thread.sleep trong thử nghiệm nói chung là một ý tưởng tồi. Nó tạo ra các bài kiểm tra giòn có thể thất bại không thể đoán trước tùy thuộc vào môi trường ("Đạt trên máy của tôi!") Hoặc tải. Không dựa vào thời gian (sử dụng mocks) hoặc sử dụng các thư viện như Awaitility để kiểm tra không đồng bộ.