2016-11-09 44 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等單元測試的一些示例。有一個清晰的結構給出/何時/那麼。在使單元測試按預期工作方面,什麼是「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; 
    } 
});