web-dev-qa-db-fra.com

Comment puis-je faire un test JUnit attendre?

J'ai un test JUnit que je veux faire attendre pendant un certain temps, de manière synchrone. Mon test JUnit ressemble à ceci:

@Test
public void testExipres(){
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExipration("foo", 1000);
    //WAIT FOR 2 SECONDS
    assertNull(sco.getIfNotExipred("foo"));
}

J'ai essayé Thread.currentThread (). Wait (), mais il jette une exception IllegalMonitorStateException (comme prévu). Y at-il une astuce ou ai-je besoin d'un autre moniteur?

72
Kylar

Que diriez-vous de Thread.sleep(2000);? :)

109
Muel

Thread.sleep () pourrait fonctionner dans la plupart des cas, mais généralement si vous attendez, vous attendez réellement qu'une condition ou un état particulier se produise. Thread.sleep () ne garantit pas que tout ce que vous attendez a bien eu lieu.

Si vous attendez une demande de repos, par exemple, elle revient généralement dans les 5 secondes, mais si vous réglez votre sommeil sur 5 secondes le jour où votre demande revient dans les 10 secondes, votre test échouera.

Pour remédier à cela, JayWay a un grand utilitaire appelé Awatility , qui est parfait pour s’assurer qu’une condition particulière survient avant de continuer.

Il a une belle api couramment aussi bien

await().until(() -> 
{
    return yourConditionIsMet();
});  

https://github.com/jayway/awaitility

52
Ben Glasser

Si votre analyseur de code statique (comme SonarQube) se plaint, mais que vous ne pouvez pas penser à une autre façon, plutôt que de dormir, vous pouvez essayer avec un hack comme: Awaitility.await().pollDelay(Duration.ONE_SECOND).until(() -> true); C'est conceptuellement incorrect, mais c'est la même chose Thread.sleep(1000).

La meilleure façon, bien sûr, est de passer un Callable, avec votre condition appropriée, plutôt que true, que j'ai.

https://github.com/awaitility/awaitility

4
rastaman

Vous pouvez également utiliser l'objet CountDownLatch comme expliqué ici .

4
Pierre Voisin

Vous pouvez utiliser la bibliothèque Java.util.concurrent.TimeUnit qui utilise en interne Thread.sleep. La syntaxe devrait ressembler à ceci:

@Test
public void testExipres(){
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExipration("foo", 1000);

    TimeUnit.MINUTES.sleep(2);

    assertNull(sco.getIfNotExipred("foo"));
}

Cette bibliothèque fournit une interprétation plus claire pour l'unité de temps. Vous pouvez utiliser 'HEURES'/'MINUTES'/'SECONDES'.

2
Akshay Pagar

Il y a un problème général: il est difficile de se moquer du temps. En outre, il est vraiment déconseillé de placer un code long en attente/en attente 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 maquette multi-threading avancée pour Clock est beaucoup plus complexe, bien sûr, mais vous pouvez le créer avec les références ThreadLocal et une bonne stratégie de synchronisation temporelle, par exemple.

0
Dávid Horváth