Hay un problema general: es difícil burlarse del tiempo. Además, es una mala práctica colocar un código de larga ejecución / espera en una prueba unitaria.
Entonces, para hacer que una API de programación se pueda probar, utilicé una interfaz con una implementación real y una simulación como esta:
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);
}
}
Con esto, podrías imitar el tiempo en tu prueba:
@Test
public void testExipres() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
clock.sleep(2000)
assertNull(sco.getIfNotExpired("foo"));
}
Un simulacro avanzado de subprocesos múltiples Clock
es mucho más complejo, por supuesto, pero puedes hacerlo con ThreadLocal
referencias y una buena estrategia de sincronización de tiempo, por ejemplo.
Thread.sleep
decir algo como Usar Thread.sleep en una prueba es generalmente una mala idea. Crea pruebas frágiles que pueden fallar de manera impredecible según el entorno ("¡Pasa en mi máquina!") O la carga. No confíe en el tiempo (use simulacros) ni use bibliotecas como Awaitility para pruebas asincrónicas.