1. Información general
Este tutorial muestra cómo utilizar ArgumentMatcher y en qué se diferencia de ArgumentCaptor .
Para obtener una introducción al marco de Mockito, consulte este artículo.
2. Dependencias de Maven
Necesitamos agregar un solo artefacto:
org.mockito mockito-core 2.21.0 test
La última versión de Mockito se puede encontrar en Maven Central .
3. ArgumentMatchers
Es posible configurar un método simulado de varias formas. Uno de ellos es devolver valores fijos:
doReturn("Flower").when(flowerService).analyze("poppy");
En el ejemplo anterior, la cadena "Flor" se devuelve solo cuando el servicio de análisis recibe la cadena "amapola".
Pero tal vez necesitemos responder a una gama más amplia de valores o valores desconocidos de antemano .
En todos estos escenarios, podemos configurar nuestros métodos simulados con comparadores de argumentos :
when(flowerService.analyze(anyString())).thenReturn("Flower");
Ahora, debido al comparador de argumentos anyString, el resultado será el mismo sin importar el valor que pasemos para analizar. ArgumentMatchers nos permite una verificación o stubbing flexible.
En caso de que un método tenga más de un argumento, no es posible utilizar ArgumentMatchers solo para algunos de los argumentos . Mockito requiere que proporciones todos los argumentos, ya sea por comparadores o por valores exactos.
Un siguiente ejemplo es un enfoque incorrecto para esto:
abstract class FlowerService { public abstract boolean isABigFlower(String name, int petals); } FlowerService mock = mock(FlowerService.class); when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);
Para solucionarlo y mantener el nombre de cadena "poppy" como se desee, usaremos eq matcher :
when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);
Hay dos puntos más a tener en cuenta cuando se utilizan los emparejadores :
- No podemos usarlos como un valor de retorno , se requiere un valor exacto cuando se aprueban llamadas
- Por último, no podemos utilizar comparadores de argumentos fuera de la verificación o el apéndice
En el último caso, Mockito detectará el argumento fuera de lugar y lanzará una InvalidUseOfMatchersException .
Un mal ejemplo podría ser:
String orMatcher = or(eq("poppy"), endsWith("y")); verify(mock).analyze(orMatcher);
La forma de implementar el código anterior es:
verify(mock).analyze(or(eq("poppy"), endsWith("y")));
Mockito también proporciona AdditionalMatchers para implementar operaciones lógicas comunes ('not', 'y', 'o') en ArgumentMatchers que coinciden con tipos primitivos y no primitivos:
verify(mock).analyze(or(eq("poppy"), endsWith("y")));
4. Coincidencia de argumentos personalizados
Crear nuestro comparador puede ser bueno para seleccionar el mejor enfoque posible para un escenario dado y producir una prueba de la más alta calidad , que sea limpia y fácil de mantener.
Por ejemplo, podríamos tener un MessageController que entrega mensajes. Recibirá un MessageDTO y, a partir de ahí, creará un mensaje para ser entregado por MessageService .
Nuestra verificación será simple, verifique que llamamos al MessageService exactamente 1 vez con cualquier Mensaje:
verify(messageService, times(1)).deliverMessage(any(Message.class));
Debido a que el mensaje se construye dentro del método bajo prueba , estamos obligados a usar any como comparador .
Este enfoque no nos permite validar los datos dentro del mensaje , que pueden ser diferentes en comparación con los datos dentro de MessageDTO .
Por esa razón, vamos a implementar un comparador de argumentos 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; } }
Para usar nuestro comparador, necesitamos modificar nuestra prueba y reemplazar cualquiera por argThat :
verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));
Ahora sabemos que nuestra instancia de Message tendrá los mismos datos que nuestro MessageDTO .
5. Coincidencia de argumentos personalizados frente a ArgumentCaptor
Ambas técnicas, los comparadores de argumentos personalizados y ArgumentCaptor se pueden usar para asegurarse de que ciertos argumentos se pasen a los simulacros.
Sin embargo, ArgumentCaptor puede encajar mejor si lo necesitamos para afirmar los valores de los argumentos para completar la verificación o si es probable que nuestro comparador de argumentos personalizado no se reutilice .
Los comparadores de argumentos personalizados a través de ArgumentMatcher suelen ser mejores para el stubbing.
6. Conclusión
En este artículo, hemos explorado una característica de Mockito , ArgumentMatcher y su diferencia con ArgumentCaptor .
Como siempre, el código fuente completo de los ejemplos está disponible en GitHub.