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


93

同期的に一定時間待機させたい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がスローされます(予想通り)。何かトリックはありますか、それとも別のモニターが必要ですか?

回答:


117

いかがThread.sleep(2000);ですか?:)


14
sonarqubeのようなコード分析ツールを使用している場合、テストでのThread.sleepの使用のThread.sleepようなもの は一般に悪い考えです。環境(「マシン上のパス!」)または負荷によっては予期せず失敗する可能性がある脆弱なテストを作成します。タイミングに依存しない(モックを使用)か、非同期テストにAwaitilityなどのライブラリを使用しないでください。
FuryFart

3
この回答は削除し、有害と見なしてください。以下のはるかに良い答えは、stackoverflow.com
a / 35163873/1229735

71

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

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

このJayWayを改善するには、Awatilityと呼ばれる優れたユーティリティがあり、次に進む前に特定の状態が発生することを保証するのに最適です。

それは素晴らしい流暢なAPIも持っています

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

https://github.com/jayway/awaitility


Android Studioでコンパイルするための待機時間が取れませんでした。
IgorGanapolsky

この行をgradleファイルに追加しましたか:compile 'org.awaitility:awaitility:3.0.0'?
Samoht 2017年

番号。これを、特定の条件を待機するテストケースに追加します
Ben Glasser

15

静的コードアナライザー(SonarQubeなど)からのクレームがあり、スリープ以外の方法を考えることができない場合は、次のようなハックを試すことができます。 Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true); これは概念的には正しくありませんが、と同じThread.sleep(1000)です。

もちろん、最善の方法は、true私が持っているではなく、適切な条件でCallableを渡すことです。

https://github.com/awaitility/awaitility


@Jitendra:Awaitilityは以前はDurationクラスを持っていたが、バージョン4以降は名前をに変更したことに注意してくださいDurations
Jacob van Lingen

注意点の1つは、ポーリング遅延を10秒以上にしたい場合は、タイムアウトをデフォルトのタイムアウトである10秒以上に増やしてください。待機時間がタイムアウトがポーリング遅延よりも短いことを警告するためです。
フォーカス

12

内部で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」を使用できます。


テスト内からワーカースレッドを開始すると、ワーカースレッドにsleep()影響がありますか?
アンソニーコング


0

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

したがって、スケジューリング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、たとえば、参照と適切な時間同期戦略を使用して作成できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.