2011-09-29 38 views
5

以下は、私のアプリケーションの簡単な設定です。 Foobarクラスは、データを取得するファサードメソッドを呼び出します。その後ファサードはWebサービスを呼び出して実際にデータを取得し、データを少し操作してFoobarに返します。非同期メソッド呼び出しのテスト

Webサービスが実行するには時間がかかるため、ファサードへのメソッド呼び出しは非同期である必要があります。したがってファサードのメソッドには戻り値がありませんが、代わりにメソッドはコールバックオブジェクトを使用します。この例を見て、以下をお読みください。

public class Foobar { 
    private List<DTO> dtos; 

    @Autowired 
    private Facade facade; 

    public void refresh() { 
     facade.refreshFoobar(new CallBack() { 
      public void dataFetched(List<DTO> dtos) { 
       setDtos(dtos); 
      } 

     }); 
    }  

    public void setDtos(List<DTO> dtos) { 
     this.dtos = dtos; 
    } 
} 


public class Facade { 

    ... 

    public void refreshFoorbar(CallBack cb) { 
     // Fetch data from a web service 
     List<DTO> dtos = webService.getData(); 
     // Manipulate DTOs 
     .... 
     // call on the callback method 
     cb.dataFecthed(dtos); 
    } 

} 

私は手動でスレッドを作成することによって、または注釈@Asyncスプリングを使用するか、ファサードのメソッドの非同期を作る2つの方法があります。

public class Facade { 

    public void refreshFoorbar(CallBack cb) { 
     new Thread() { 

      @Override 
      public void run() { 
       .... 
      } 

     }.start(); 

    } 
} 

// ... OR ... 

public class Facade { 

    @Async 
    public void refreshFoorbar(CallBack cb) { 
     ....  
    } 
} 

私の問題は、このメソッド呼び出しの連鎖のための統合テストを書く必要があることです。私は、統合テストが実行されたときに非同期ファサードコールを同期させる必要があると思う。そうでなければ、適切なアサートをいつ行うことができるかわからない。メソッド呼び出しを同期させるための唯一のアイデアは、手動で処理されるスレッドを使用してスレッドを条件付きにすることです(テスト目的のためにファサードメソッドを別のスレッドで実行するかどうかを決定するif節があります)。

しかし、春のように私の方法を同期させるより良い方法であろうと、何らかの方法でマルチスレッドをテストすることによって、私の問題はより良い解決策になるかもしれません。

これは私があなたの提案を必要とするところです。どうすれば問題を解決できますか?注意すべき点は、ユニットテストと統合テストの両方でjunitを使用していることです。

+0

正しい方法であるかどうかわかりません。通常、非同期条件のテストは、非同期タスクを起動し、しばらく待ってから、タスクが完了したかどうかをテストします。 – SJuan76

答えて

6

このようなJUnitのテストでは、コールバックによってカウントダウンされるCountDownLatchのテストコールバックを使用し、テストメソッドによってawait()をテストします。

private static class TestingCallback implements Callback { 
    private final CountDownLatch latch; 
    public TestingCallback(CountDownLatch latch) { 
     this.latch = latch; 
    } 
    @Override public void onEvent() { 
     this.latch.countDown(); 
    } 
} 

@Test 
public void testCallback() { 
    final CountDownLatch latch = new CountDownLatch(1); 

    classUnderTest.execute(new TestCallback(latch)); 

    assertTrue(latch.await(30, TimeUnit.SECONDS)); 
} 

コールバックはテスト対象コード、ラッチ戻りtrueとテストパスで(非同期で)呼び出された場合。コールバックが呼び出されない場合、テストは30秒後にタイムアウトし、アサーションは失敗します。

12

簡単な解決策は

@Async 
public Future<String> refreshFoorbar(CallBack cb) { 
    yourHeavyLifting(); //asynchronous call 
    return new AsyncResult<String>("yourJobNameMaybe"); 
} 

そして、あなたのテストでは、将来の参照を取得し、get()メソッドを呼び出して、このような将来のオブジェクトを返すようになります。

future.get(); // if its not already complete, waits for it to complete 
assertTrue(yourTestCondition) 

blog postはサンプルを示す。

+0

これが役立つ場合はこちらを参照してください。http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tejb_clientcode.html –

関連する問題