2016-07-20 11 views
0

現在、SUT(System Under Test)が要求を外部システムに適切に送信しているかどうかを確認したいと考えています。私はQA環境(HTTPを介した外部モック)とQA環境のメッセージキューを使用しています(コンフィグレーションによって実際のシステムと交換できます)。Thread.sleep以外の非同期テスト

問題:これらの外部システムでアサーションを行うには、統合テストでthread.sleep()を広げていますが、それは悪いです。私はこれをコールバックの要求に置き換え、その要求に対するリスナを提供するテストスイートにしたいと思います。これにはすでに解決策がありますか?

+1

[Awaitility](https://github.com/awaitility/awaitility)と[ConcurrentUnit](https://github.com/jhalterman/concurrentunit)の2つのツールが役に立ちます。 – Jonathan

答えて

1

ここで説明するシナリオでは、クラスjava.util.concurrent.CyclicBarrierのインスタンスの使用をお勧めします - 非同期的に計算を行うスレッドの次の簡単な例を参照してください(ここでは、「パーセント完了」値を最初に50に設定し、 〜100)、 "%done"値をメインスレッドから取得できるようにします。 、私は私のSUT(あるいは、あなたのお気に入りのAOPフレームワークを使用することができます)の2つの計算方法を傍受するMockitoのスパイで、JUnitの4を使用

public class AsyncProcess implements Runnable { 

    private int percentageDone = 0; 

    public int getPercentageDone() { return percentageDone; } 

    public void doFirstHalf() { percentageDone = 50; } 

    public void doSecondHalf() { percentageDone = 100; } 

    public void run() { 
    doFirstHalf(); 
    doSecondHalf(); 
    } 

} 

ユニットテスト、これをするために:

はここでSUTクラスです。

import static org.hamcrest.Matchers.is; 
import static org.junit.Assert.assertThat; 
import static org.mockito.Mockito.doAnswer; 

import java.util.concurrent.CyclicBarrier; 

import org.junit.Test; 
import org.mockito.Mockito; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class AsyncProcessTest { 

    @Test 
    public void testExecute() throws Exception { 

    final CyclicBarrier firstHalfStarted = new CyclicBarrier(2); 
    final CyclicBarrier firstHalfFinished = new CyclicBarrier(2); 
    final CyclicBarrier secondHalfStarted = new CyclicBarrier(2); 
    final CyclicBarrier secondHalfFinished = new CyclicBarrier(2); 

    AsyncProcess process = Mockito.spy(new AsyncProcess()); 

    doAnswer(new Answer() { 
     public Object answer(InvocationOnMock invocation) throws Throwable { 
     firstHalfStarted.await(); 
     invocation.callRealMethod(); 
     firstHalfFinished.await(); 
     return null; 
     } 
    }).when(process).doFirstHalf(); 

    doAnswer(new Answer() { 
     public Object answer(InvocationOnMock invocation) throws Throwable { 
     secondHalfStarted.await(); 
     invocation.callRealMethod(); 
     secondHalfFinished.await(); 
     return null; 
     } 
    }).when(process).doSecondHalf(); 

    new Thread(process, "AsyncProcess").start(); 

    assertThat(process.getPercentageDone(), is(0)); 

    firstHalfStarted.await(); 
    firstHalfFinished.await(); 

    assertThat(process.getPercentageDone(), is(50)); 

    secondHalfStarted.await(); 
    secondHalfFinished.await(); 

    assertThat(process.getPercentageDone(), is(100)); 
    } 

} 

このアプローチでは、関係するスレッドの実行フローをきめ細かく制御できます。 CyclicBarriersのペアをカプセル化し、インターセプトコールを抽出し、タイムアウトと適切な例外処理のサポートを抽出することで、「マイクロフレームワーク」に容易に拡張できます。