2016-11-09 18 views
0

AsyncHttpClientを使用する次のコードの単体テストを書いています。 FutureCallbackの実装でCountDownLatchの使用とCountDownLatchの減分が原因で、私のJUnitテストケースがカウントダウンラッチが減るのを待ってハングしていました。 JUnitテストでは、ArgumentCaptorを使用してFutureCallbackをキャプチャしてからthenAnswerを使用して、完了したメソッドを呼び出してカウントダウンラッチをデクリメントします。しかし、それは動作していないようだ、任意のアイデアが役立つだろう。Mockito thenAnswerが期待どおりに動作しないようです。

public List<QueryResponse> execute(Query query) { 
    List<QueryResponse> res = new ArrayList<QueryResponse>(); 

    try { 
     List<HttpRequestBase> requests = query.generateHttpRequests(); 
     List<Future<HttpResponse>> futures = new ArrayList<Future<HttpResponse>>(); 

     final CountDownLatch requestCompletionCDLatch = new CountDownLatch(requests.size()); 
     for (HttpRequestBase request : requests) { 
      futures.add(httpClient.execute(request, new FutureCallback<HttpResponse>() { 

       @Override 
       public void failed(Exception e) { 
        logger.error("Error while executing: " + request.toString(), e); 
        requestCompletionCDLatch.countDown(); 
       } 

       @Override 
       public void completed(HttpResponse result) { 
        requestCompletionCDLatch.countDown(); 
       } 

       @Override 
       public void cancelled() { 
        logger.info("Request cancelled while executing: " + request.toString()); 
        requestCompletionCDLatch.countDown(); 
       } 
      })); 
     } 

     requestCompletionCDLatch.await(); 
     for (Future<HttpResponse> future : futures) { 
      HttpResponse response = future.get(rcaRequestTimeout, TimeUnit.SECONDS); 
      int status = response.getStatusLine().getStatusCode(); 
      if (status != HttpStatus.SC_OK) { 
       logger.warn("Query with non-success status " + status); 
      } else { 
       res.add(query.parseResponse(response.getEntity().getContent())); 
      } 
     } 
    } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) { 
     logger.error("Error while querying", e); 
    } catch (URISyntaxException e) { 
     logger.error("Error while generating the query", e); 
    } 
    return res; 
} 

次のように私のユニットテストは、次のとおりです。

@Test 
public void testHttpError() throws InterruptedException, ExecutionException, TimeoutException { 
    StatusLine status = Mockito.mock(StatusLine.class); 
    when(status.getStatusCode()).thenReturn(400); 

    HttpResponse response = Mockito.mock(HttpResponse.class); 
    when(response.getStatusLine()).thenReturn(status); 

    Future<HttpResponse> future = Mockito.mock(Future.class); 
    when(future.get(anyLong(), any())).thenReturn(response); 

    CloseableHttpAsyncClient httpClient = Mockito.mock(CloseableHttpAsyncClient.class); 
    ArgumentCaptor<HttpUriRequest> requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); 
    ArgumentCaptor<FutureCallback<HttpResponse>> futureCallbackCaptor = ArgumentCaptor.forClass((Class)FutureCallback.class); 
    when(httpClient.execute(any(), any())).thenReturn(future).thenAnswer(new Answer() { 

     @Override 
     public Object answer(InvocationOnMock invocation) throws Throwable { 
      verify(httpClient).execute(requestCaptor.capture(), futureCallbackCaptor.capture()); 
      futureCallbackCaptor.getValue().completed(response); 
      return null; 
     } 
    }); 

    StubbedRcaClient rcaClient = new StubbedRcaClient(httpClient); 
    Query query = new Query("abc", "xyz", RcaHttpRequestType.GET, 1000); 
    List<QueryResponse> res = rcaClient.execute(query); 
    assertEquals(0, res.size()); 
    IOUtils.closeQuietly(rcaClient); 
} 
+0

このテストはで検証するためのロジックを含む、非常に複雑です答え。コミュニティやメンテナンスプログラマーが理解しやすくするためにリファクタリングすることができますか?たとえば、https://dzone.com/refcardz/mockitoのような良い単体テストの例を見てみましょう。/when/whenには明確な構造が与えられています。単体テストを期待どおりに動作させるには、 'StubbedRcaClient'は何で、' httpClient'に正しく委譲されていますか?また、 'Future'を模倣しないでください - コールバックが' get(long、TimeUnit) 'や' Future'の中の別のメソッドを使用しているかどうかわからない –

+0

私はHttpAsyncClientからの応答を模擬しようとしています。あなたは何をお勧めしますか? – KunalC

+0

https://stackoverflow.com/questions/13866533/how-to-create-a-completed-future-in-java –

答えて

0

私は次のように私のJUnitを更新することによって、この作品を作った:

when(httpClient.execute(any(), any())).thenAnswer(new Answer<Future<HttpResponse>>() { 

    @Override 
    public Future<HttpResponse> answer(InvocationOnMock invocation) throws Throwable { 
     verify(httpClient).execute(requestCaptor.capture(), futureCallbackCaptor.capture()); 
     futureCallbackCaptor.getValue().completed(response); 
     return future; 
    } 
}); 
関連する問題