Mockito ArgumentMatchers

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.