2017-01-25 33 views
3

我正在學習Java 8 CompletableFuture,並以此結束。第一步,你對這行代碼有什麼看法?我需要並行發送請求到不同的服務,然後等待所有人響應並繼續工作。CompletableFuture可用性和單元測試

//service A 
CompletableFuture<ServiceAResponse> serviceAFuture = CompletableFuture.supplyAsync(
    () -> this.ServiceA.retrieve(serviceARequest), serviceAExecutorService 
); 

//service B 
CompletableFuture<ServiceBResponse> serviceBFuture = CompletableFuture.supplyAsync(
    () -> this.ServiceB.retrieve(serviceBRequest), serviceBExecutorService 
); 

CompletableFuture.allOf(serviceAFuture, serviceBFuture).join(); 
ServiceAResponse responseA = serviceAFuture.join(); 
ServiceBResponse responseB = serviceBFuture.join(); 

即使代碼正在做我想做的事,我在測試代碼所在的類時遇到問題。我嘗試使用的Mockito和做類似:

doAnswer(invocation -> CompletableFuture.completedFuture(this.serviceAResponse)) 
    .when(this.serviceAExecutorService) 
    .execute(any()); 

在哪裏執行程序服務的服務響應嘲諷,但測試永遠不會結束,並且線程保持在這條線在等待着什麼

CompletableFuture.allOf(serviceAFuture, serviceBFuture).join(); 

上的任何暗示什麼我在這裏失蹤?謝謝!

回答

4

如果我是你,我會簡單地嘲笑服務A和B以及你的執行者,然後註釋他們,這要歸功於註釋@InjectMocks,因爲他們是你班級的領域。

如果你想嘲笑你Executor的方法execute,你倒是應該繼續作爲下一簡單地調用該方法提供Runnablerun

doAnswer(
    (InvocationOnMock invocation) -> { 
     ((Runnable) invocation.getArguments()[0]).run(); 
     return null; 
    } 
).when(serviceAExecutorService).execute(any(Runnable.class)); 

所以基本上你的測試將是這樣的:

@RunWith(MockitoJUnitRunner.class) 
public class CompletableFutureServiceTest { 

    // The mock of my service A 
    @Mock 
    private ServiceA ServiceA; 
    // The mock of my service B 
    @Mock 
    private ServiceB ServiceB; 
    // The mock of your executor for the service A 
    @Mock 
    private Executor serviceAExecutorService; 
    // The mock of your executor for the service B 
    @Mock 
    private Executor serviceBExecutorService; 
    // My class in which I want to inject the mocks 
    @InjectMocks 
    private CompletableFutureService service; 

    @Test 
    public void testSomeMethod() { 
     // Mock the method execute to call the run method of the provided Runnable 
     doAnswer(
      (InvocationOnMock invocation) -> { 
       ((Runnable) invocation.getArguments()[0]).run(); 
       return null; 
      } 
     ).when(serviceAExecutorService).execute(any(Runnable.class)); 
     doAnswer(
      (InvocationOnMock invocation) -> { 
       ((Runnable) invocation.getArguments()[0]).run(); 
       return null; 
      } 
     ).when(serviceBExecutorService).execute(any(Runnable.class)); 

     ServiceAResponse serviceAResponse = ... // The answer to return by service A 
     // Make the mock of my service A return my answer 
     when(ServiceA.retrieve(any(ServiceARequest.class))).thenReturn(
      serviceAResponse 
     ); 
     ServiceBResponse serviceBResponse = ... // The answer to return by service B 
     // Make the mock of my service B return my answer 
     when(ServiceB.retrieve(any(ServiceBRequest.class))).thenReturn(
      serviceBResponse 
     ); 

     // Execute my method 
     ServiceResponse response = service.someMethod(
      new ServiceARequest(), new ServiceBRequest() 
     ); 

     // Test the result assuming that both responses are wrapped into a POJO 
     Assert.assertEquals(serviceAResponse, response.getServiceAResponse()); 
     Assert.assertEquals(serviceBResponse, response.getServiceBResponse()); 
    } 
} 
+0

這樣做,我得到NPE,因爲我模仿我的ExecutorService(我使用一個自定義),但如果我用一個moked一個,測試永遠不會結束。 當然,如果我使用默認的執行器服務,而不發送我的CompletableFuture.supplyAsync(),它就像一個魅力。 – Leo

+1

回覆更新,請再次查看 –

+1

YES!謝謝!這就是我一直想要嘲笑ExecutionService.execute()方法的原因嗎?這正是我想要做的,但它的工作方式。 – Leo