2017-01-25 3 views
3

Я узнаю о java 8 CompletableFuture и закончил с этим.CompletedFuture удобство использования и модульный тест

Кулак всего, что вы думаете об этих строках кода? Мне нужно отправить запрос на разные службы параллельно, а затем дождаться ответа всех и продолжить работу.

//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, поскольку они являются полями вашего класса.

Если вы хотите издеваться метод execute вашего Executor, вы должны достаточно выполнить следующий просто вызвать метод run предоставленного Runnable:

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 (я использую пользовательский), но если я использую выкромку, тест никогда не заканчивается. Конечно, если я использую службу исполнителя по умолчанию, не отправляя мой на CompletableFuture.supplyAsync(), он работает как шарм. – Leo

+1

Ответ обновлен, пожалуйста, проверьте еще раз –

+1

ДА! Спасибо! это то, что я должен делать всегда. Я хочу высмеять метод ExecutionService.execute()? Это именно то, что я пытался сделать, но так, как это работает. – Leo

Смежные вопросы