Testando retornos de chamada com o Mockito
1. Visão geral
2. Introdução aos retornos de chamada
A callback is a piece of code that is passed as an argument to a method, which is expected to call back (execute) the argument at a given time.
Essa execução pode ser imediata como em um retorno de chamada síncrono, mas mais tipicamente pode ocorrer posteriormente, como em um retorno de chamada assíncrono.
Um cenário comum para o uso de Callbacks éduring service interactions when we need to process the response from a service call.
Neste tutorial, usaremos a interfaceService mostrada abaixo como o colaborador em casos de teste:
public interface Service {
void doAction(String request, Callback callback);
}
No argumentoCallback, passamos uma classe que tratará a resposta usando o métodoreply(T response):
public interface Callback {
void reply(T response);
}
2.1. Um serviço simples
Também usaremos umservice example to demonstrate how to pass and invoke the callback direto:
public void doAction() {
service.doAction("our-request", new Callback() {
@Override
public void reply(Response response) {
handleResponse(response);
}
});
}
O métodohandleResponse verifica se a resposta é válida antes de adicionar alguns dados ao objetoResponse:
private void handleResponse(Response response) {
if (response.isValid()) {
response.setData(new Data("Successful data response"));
}
}
Para maior clareza, optamos por não usar uma expressão Java Lamda, masservice.doActioncall could also be written more concisely:
service.doAction("our-request", response -> handleResponse(response));
Para saber mais sobre as expressões Lambda, dê uma olhada emhere.
3. Usando umArgumentCaptor
Agora vamos olhar parahow we use Mockito to grab the Callback object using an*ArgumentCaptor*:
@Test
public void givenServiceWithValidResponse_whenCallbackReceived_thenProcessed() {
ActionHandler handler = new ActionHandler(service);
handler.doAction();
verify(service).doAction(anyString(), callbackCaptor.capture());
Callback callback = callbackCaptor.getValue();
Response response = new Response();
callback.reply(response);
String expectedMessage = "Successful data response";
Data data = response.getData();
assertEquals(
"Should receive a successful message: ",
expectedMessage, data.getMessage());
}
Neste exemplo, primeiro criamos umActionHandler antes de chamar o métododoAction deste manipulador. This is simply a wrapper to our Simple Service doAction method call que é onde invocamos nosso callback.
Em seguida, verificamos quedoAction was chamou nossa instância de serviço simulada, passandoanyString() como o primeiro argumento ecallbackCaptor.capture() as the second, which is where we capture the Callback object. O métodogetValue() pode então ser usado para retornar o valor capturado do argumento.
Agora que temos o objetoCallback, criamos um objetoResponse que é válido por padrão antes decall the reply method directly and assert that the response data has the correct value.
4. Usando o métododoAnswer()
Agora vamos olhar para umcommon solution for stubbing methods that have callbacks usandoAnswer object and doAnswer method to stub the void methoddoAction: do Mockito
@Test
public void givenServiceWithInvalidResponse_whenCallbackReceived_thenNotProcessed() {
Response response = new Response();
response.setIsValid(false);
doAnswer((Answer) invocation -> {
Callback callback = invocation.getArgument(1);
callback.reply(response);
Data data = response.getData();
assertNull("No data in invalid response: ", data);
return null;
}).when(service)
.doAction(anyString(), any(Callback.class));
ActionHandler handler = new ActionHandler(service);
handler.doAction();
}
E, em nosso segundo exemplo, primeiro criamos um objetoResponse inválido que será usado posteriormente no teste.
Em seguida, configuramosAnswer em nosso serviço simulado para que, quandodoAction for chamado,we intercept the invocation and grab the method arguments using invocation.getArgument(1) obtenha o argumentoCallback.
A última etapa é criarActionHandler and calldoAction que faz com queAnswer seja invocado.
Para saber mais sobre métodos de stub de void, dê uma olhada emhere.
3. Conclusão
Neste breve artigo, abordamos duas maneiras diferentes de abordar os retornos de chamada de teste ao testar com o Mockito.
Como sempre, os exemplos estão disponíveis nesteGitHub project.