web-dev-qa-db-ja.com

JUnitテストを待機させるにはどうすればよいですか?

同期的に一定の時間待機したいJUnitテストがあります。私のJUnitテストは次のようになります。

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

Thread.currentThread()。wait()を試しましたが、IllegalMonitorStateExceptionがスローされます(予想どおり)。それにいくつかのトリックがありますか、または別のモニターが必要ですか?

72
Kylar

Thread.sleep(2000);はどうですか? :)

109
Muel

Thread.sleep()はほとんどの場合に機能しますが、通常、待機している場合、実際には特定の条件または状態が発生するのを待っています。 Thread.sleep()は、あなたが待っていることが実際に起こったことを保証しません。

たとえば、休憩リクエストを待っている場合、通常5秒で戻りますが、10秒でリクエストが戻ってくる日を5秒間スリープに設定すると、テストは失敗します。

この問題を解決するために、JayWayには Awatility と呼ばれる優れたユーティリティがあります。これは、先に進む前に特定の状態を確実に発生させるのに最適です。

素敵な流なapiもあります

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

https://github.com/jayway/awaitility

52
Ben Glasser

また、説明されている here のようなCountDownLatchオブジェクトを使用することもできます。

4
Pierre Voisin

内部でThread.sleepを使用するJava.util.concurrent.TimeUnitライブラリを使用できます。構文は次のようになります。

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

    TimeUnit.MINUTES.sleep(2);

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

このライブラリは、時間単位のより明確な解釈を提供します。 「HOURS」/「MINUTES」/「SECONDS」を使用できます。

2
Akshay Pagar

一般的な問題があります:時間をモックするのは難しいです。また、単体テストに長時間実行/待機中のコードを配置することは非常に悪い習慣です。

したがって、スケジューリングAPIをテスト可能にするために、次のような実際の実装と模擬実装のインターフェースを使用しました。

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

}

これにより、テストの時間を模倣できます。

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

Clockの高度なマルチスレッドモックはもちろんはるかに複雑ですが、たとえばThreadLocal参照と適切な時間同期戦略を使用して作成できます。

0
Dávid Horváth