2017-01-25 32 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