Mockito ArgumentMatchers
1. Visão geral
Este tutorial mostrahow to use the ArgumentMatcher and how it differs from the ArgumentCaptor.
Para obter uma introdução à estrutura Mockito, consulteto this article.
2. Dependências do Maven
Precisamos adicionar um único artefato:
org.mockito
mockito-core
2.21.0
test
A versão mais recente deMockito pode ser encontrada emMaven Central.
3. ArgumentMatchers
É possível configurar um método simulado de várias maneiras. Uma delas é retornar valores fixos:
doReturn("Flower").when(flowerService).analyze("poppy");
No exemplo acima, aString “Flor” é retornada apenas quando o serviço de análise recebe aString “papoula”.
Masmaybe we need to respond to a wider range of values or beforehand unknown values.
Em todos esses cenários,we can configure our mocked methods with argument*matchers*:
when(flowerService.analyze(anyString())).thenReturn("Flower");
Agora, por causa do matcher de argumentoanyString, o resultado será o mesmo, não importa o valor que passarmos para analisar. ArgumentMatchers nos permite verificação flexível ou stub.
No caso de um método ter mais de um argumento,it isn’t possible to use ArgumentMatchers for only some of the arguments. Mockito requer que você forneça todos os argumentos pormatchers ou por valores exatos.
Um próximo exemplo é uma abordagem incorreta para isso:
abstract class FlowerService {
public abstract boolean isABigFlower(String name, int petals);
}
FlowerService mock = mock(FlowerService.class);
when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);
Para consertar e manter o nome deString “papoula” como desejado, usaremoseq matcher:
when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);
Existem mais dois pontos a serem tomados quandomatchers é usado:
-
We can’t use them as a return value, um valor exato é necessário ao fazer o stub das chamadas
-
Finalmente,we can’t use argument matchers outside of verification or stubbing
No último caso,Mockito detectará o argumento mal colocado e lançará umInvalidUseOfMatchersException.
Um mau exemplo pode ser:
String orMatcher = or(eq("poppy"), endsWith("y"));
verify(mock).analyze(orMatcher);
A maneira de implementar o código acima é:
verify(mock).analyze(or(eq("poppy"), endsWith("y")));
Mockito também forneceAdditionalMatchers para implementar operações lógicas comuns (‘não’, ‘e’, ‘ou’) emArgumentMatchers que correspondem a tipos primitivos e não primitivos:
verify(mock).analyze(or(eq("poppy"), endsWith("y")));
4. Correspondente de argumento personalizado
Criandoour matcher can be good to select the best possible approach for a given scenario and produce highest quality test, que é limpo e sustentável.
Por exemplo, poderíamos ter umMessageController que entrega mensagens. Ele receberá umMessageDTO e, a partir disso, criará umMessage para ser entregue porMessageService.
Nossa verificação será simples, verifique se chamamosMessageService exatamente 1 vez comany Message:
verify(messageService, times(1)).deliverMessage(any(Message.class));
Porquethe Message is constructed inside the method under test, somos forçados a usarany comomatcher.
Essa abordagem não nos permite validar os dados dentro deMessage,which can be different compared to the data inside MessageDTO.
Por esse motivo, vamos implementar um matcher de argumento personalizado:
public class MessageMatcher implements ArgumentMatcher {
private Message left;
// constructors
@Override
public boolean matches(Message right) {
return left.getFrom().equals(right.getFrom()) &&
left.getTo().equals(right.getTo()) &&
left.getText().equals(right.getText()) &&
right.getDate() != null &&
right.getId() != null;
}
}
To use our matcher, we need to modify our test and replace any by argThat:
verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));
Agora sabemos que nossa instânciaMessage terá os mesmos dados que nossaMessageDTO.
5. Correspondente de argumento personalizado vs. ArgumentCaptor
Ambas as técnicascustom argument matchers eArgumentCaptor podem ser usadas para garantir que certos argumentos foram passados para simulações.
No entanto,ArgumentCaptor may be a better fit if we need it to assert on argument values para concluir a verificaçãoor our custom argument matcher is not likely to be reused.
Custom argument matchers viaArgumentMatcher são geralmente melhores para stub.
6. Conclusão
Neste artigo, exploramos um recurso deMockito, ArgumentMatcher e sua diferença comArgumentCaptor.
Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.