Il y a un problème général: il est difficile de se moquer du temps. En outre, il est très mauvais de placer du code à exécution / attente longue dans un test unitaire.
Donc, pour rendre une API de planification testable, j'ai utilisé une interface avec une implémentation réelle et fictive comme celle-ci:
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);
}
}
Avec cela, vous pouvez imiter le temps dans votre test:
@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"));
}
Une simulation multi-threading avancée Clock
est bien sûr beaucoup plus complexe, mais vous pouvez la créer avec des ThreadLocal
références et une bonne stratégie de synchronisation de l'heure, par exemple.
Thread.sleep
dire quelque chose comme Utiliser Thread.sleep dans un test est généralement une mauvaise idée. Il crée des tests fragiles qui peuvent échouer de manière imprévisible en fonction de l'environnement ("Passe sur ma machine!") Ou de la charge. Ne vous fiez pas au timing (utilisez des simulations) ou n'utilisez pas de bibliothèques telles que Awaitility pour les tests asynchrones.