Genel bir sorun var: Zamanla dalga geçmek zor. Ayrıca, uzun çalışma / bekleme kodunu bir birim testine yerleştirmek gerçekten kötü bir uygulamadır.
Bu nedenle, bir programlama API'sini test edilebilir hale getirmek için, gerçek ve şunun gibi sahte bir uygulamaya sahip bir arayüz kullandım:
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);
}
}
Bununla, testinizde zamanı taklit edebilirsiniz:
@Test
public void testExipres() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
clock.sleep(2000)
assertNull(sco.getIfNotExpired("foo"));
}
Gelişmiş bir çoklu iş parçacığı Clock
modeli elbette çok daha karmaşıktır, ancak bunu ThreadLocal
örneğin referanslar ve iyi bir zaman senkronizasyonu stratejisi ile yapabilirsiniz.
Thread.sleep
gibi bir şey söylemekten şikayet edeceklerdir . Genellikle kötü bir fikirdir. Ortama ("Makinemden geçer!") Veya yüke bağlı olarak beklenmedik şekilde başarısız olabilen kırılgan testler oluşturur. Zamanlamaya güvenmeyin (taklitler kullanın) veya eşzamansız testler için Bekleme gibi kitaplıkları kullanmayın.