Hoe kan ik een Junit-test laten wachten?

Ik heb een Junit-test die ik wil wachten op een periode van tijd synchroon. Mijn Junit-test ziet er als volgt uit:

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

Ik heb de Thread.currentThread().wait(), maar het gooit een illegaalmonitorstatexception (zoals verwacht).

Is er een truc voor of heb ik een andere monitor nodig?


Antwoord 1, Autoriteit 100%

Hoe zit het met Thread.sleep(2000);? 🙂


Antwoord 2, Autoriteit 83%

Thread.Sleep () zou in de meeste gevallen kunnen werken, maar meestal als u wacht, wacht u daadwerkelijk op een bepaalde toestand of staat om optreden. Thread.Sleep () garandeert niet dat waar je ook op wacht, daadwerkelijk is gebeurd.

Als u op een rustzoeker bijvoorbeeld wacht, kan het meestal binnen 5 seconden terugkeren, maar als u uw slaap gedurende 5 seconden instelt, wordt de dag dat uw verzoek binnen 10 seconden terugkomt, wordt uw test falen.

Om deze Jayway te verhelpen, heeft Jayway een geweldig hulpprogramma genaamd Awatility die perfect is om ervoor te zorgen dat er een specifieke toestand optreedt voordat je verder gaat.

Het heeft ook een mooie vloeiende API

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

https://github.com/jayway/awaitility


Antwoord 3, Autoriteit 24%

U kunt Java.Util.concurrent.TimeUnit-bibliotheek gebruiken die intern draagt. De syntaxis zou er als volgt uit moeten zien:

@Test
public void testExipres(){
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExipration("foo", 1000);
    TimeUnit.MINUTES.sleep(2);
    assertNull(sco.getIfNotExipred("foo"));
}

Deze bibliotheek biedt meer duidelijke interpretatie voor tijdseenheid. U kunt ‘uur /’ minuten ‘/’ seconden ‘gebruiken.


Antwoord 4, Autoriteit 20%

Indien uw statische codeanalysator (zoals Sonarqube) klachten, maar u kunt niet aan een andere manier bedenken, in plaats van slaap, kunt u proberen met een hack zoals:
Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true);
Het is conceptueel onjuist, maar het is hetzelfde als Thread.sleep(1000).

De beste manier is natuurlijk om een ​​vulbaar te maken, met uw juiste toestand, in plaats van true, die ik heb.

https://github.com/awaitility/awaitility


Antwoord 5, Autoriteit 12%

Als het een absolute must is om vertraging in een test te genereren CountDownLatchis een eenvoudige oplossing. In uw testklasse verklaren:

private final CountDownLatch waiter = new CountDownLatch(1);

en in de test waar nodig:

waiter.await(1000 * 1000, TimeUnit.NANOSECONDS); // 1ms

Misschien niet nodig om te zeggen, maar in gedachten te houden dat je wachttijden klein moet houden en niet opgespekt wacht op te veel plaatsen.


Antwoord 6, Autoriteit 5%

U kunt ook de CountDownLatchObject gebruiken zoals uitgelegd hier .


Antwoord 7, Autoriteit 2%

Er is een algemeen probleem: het is moeilijk om tijd te bespotten. Ook is het echt slechte praktijk om lange lopende / wachtcode in een eenheidstest te plaatsen.

Dus, voor het maken van een planning API-testable, heb ik een interface gebruikt met een echte en een schijn-implementatie zoals deze:

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);
    }
}

Hiermee zou je de tijd in je test kunnen nabootsen:

@Test
public void testExpiration() {
    MockClock clock = new MockClock();
    SomeCacheObject sco = new SomeCacheObject();
    sco.putWithExpiration("foo", 1000);
    clock.sleep(2000) // wait for 2 seconds
    assertNull(sco.getIfNotExpired("foo"));
}

Een geavanceerde multi-threading mock voor Clockis natuurlijk veel complexer, maar je kunt het maken met bijvoorbeeld ThreadLocalreferenties en een goede tijdsynchronisatiestrategie .

Other episodes