¿Cómo verificar que no se llamó a un método específico usando Mockito?

6 minutos de lectura

avatar de usuario
beluchin

Cómo verificar que un método es no invocado en la dependencia de un objeto?

Por ejemplo:

public interface Dependency {
    void someMethod();
}

public class Foo {
    public bar(final Dependency d) {
        ...
    }
}

Con la prueba de Foo:

public class FooTest {
    @Test
    public void dependencyIsNotCalled() {
        final Foo foo = new Foo(...);
        final Dependency dependency = mock(Dependency.class);
        foo.bar(dependency);
        **// verify here that someMethod was not called??**
    }
}

avatar de usuario
Brice

Aún más significativo:

import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

// ...

verify(dependency, never()).someMethod();

La documentación de esta función está ahí. §4 “Verificación del número exacto de invocaciones / al menos x / nunca”y el never javadoc es aquí.

  • Usando never es la mejor y más específica forma, pero si necesita verificar un objeto simulado completo, también considere verifyZeroInteractions(mockObject) o verifyNoMoreInteractions(mockObject).

    –Jeff Bowman

    12/10/2012 a las 19:18

  • ¿Qué hacer si someMethod es privado?

    – Sumit Kumar Saha

    1 de agosto de 2019 a las 13:43

  • Entonces no puedes burlarte de él en primer lugar (con Mockito) 😉 PowerMock lo permite pero es más complejo de configurar. O si tiene la propiedad del código, relaja la visibilidad al paquete.

    – Brice

    1 de agosto de 2019 a las 14:26


  • Desde 3.0.1 verifyZeroInteractions ha quedado en desuso. verifyNoInteractions es la alternativa sugerida. La versión de Mockito en el momento de este comentario es 3.3.3

    – VKB

    29 de abril de 2020 a las 17:51

avatar de usuario
beluchin

Utilice el segundo argumento de la Mockito.verify método, como en:

Mockito.verify(dependency, Mockito.times(0)).someMethod()

  • Modo de verificación estático público never () { veces de retorno (0); }

    – gbero

    25 de abril de 2017 a las 12:20

  • never() no es significativamente más legible que times(0). Pero la existencia de never aumenta la carga cognitiva y hace que el sistema mockito sea más difícil de entender y recordar cómo usarlo. Así que realmente mockito no debería haber incluido never en su API, no vale la pena el costo mental.

    – BT

    14 de enero de 2019 a las 21:56

  • Pregunta: este formulario verifica que someMethod fue llamado 0 veces, o solo verifica que someMethod nunca fue llamado con cero argumentos?

    – BT

    14 de enero de 2019 a las 21:57

  • @BT – Me imagino que verifica el someMethod con cero argumentos se llamó cero veces, no verificado.

    – beluchin

    15 de enero de 2019 a las 9:25

  • Lo mismo funciona para jmockit por cierto, times=0;

    – Fakrudin

    12 de noviembre de 2021 a las 18:47

Como patrón más general a seguir, tiendo a usar un @After bloque en la prueba:

@After
public void after() {
    verifyNoMoreInteractions(<your mock1>, <your mock2>...);
}

Entonces la prueba es libre para verificar solo lo que debería ser llamado.

Además, descubrí que a menudo me olvidaba de verificar “sin interacciones”, solo para descubrir más tarde que se estaban llamando cosas que no deberían haber sido.

Por lo tanto, este patrón me parece útil para detectar todas las llamadas inesperadas que no se han verificado específicamente.

  • La documentación de Mockito establece que no se debe abusar de este patrón: “Una palabra de advertencia: algunos usuarios que hicieron muchas burlas clásicas de esperar, ejecutar y verificar tienden a usar verificarNoMásInteracciones() con mucha frecuencia, incluso en todos los métodos de prueba. verificarNoMásInteracciones () no se recomienda su uso en todos los métodos de prueba.checkNoMoreInteractions() es una afirmación útil del kit de herramientas de prueba de interacción. Úselo solo cuando sea relevante. Abusar de él conduce a pruebas sobreespecificadas y menos fáciles de mantener”. Ver aquí

    – Chadí

    4 de marzo de 2016 a las 13:31

  • “Úsalo solo cuando sea relevante”. Siento que siempre es relevante. No veo ese patrón como abuso: como dije, encuentra que “se estaban llamando cosas que no deberían haber sido”. Para mí, esa es una pieza vital de verificación: si algo está llamando a un repositorio que no debería estar usando, ¡quiero saberlo! A menos que haya otra forma de verificar eso sin usar verifyNoMoreInteractions? Las otras respuestas aquí se basan en que el escritor de la prueba recuerde explícitamente enumerar estos controles: eso es demasiado propenso a errores en mi libro.

    – David Lavanda

    31 mayo 2016 a las 15:55

  • Vi este comentario, pero también sentí que el razonamiento no era convincente. Me encantaría leer más acerca de por qué esto no se recomienda.

    – tobinibot

    8 de noviembre de 2016 a las 4:02

  • @tobinibot Porque la idea de las pruebas unitarias es verificar un contrato. La mayoría de los contratos generalmente no involucran cuántas veces se invoca algún otro método, sino que pasar parámetros conocidos da como resultado una respuesta conocida. Al no usar más interacciones, básicamente está verificando la implementación línea por línea, lo que hace que la refactorización y la implementación sean tediosas. Que no es el punto de las pruebas unitarias.

    – Andrew T. Finnell

    21/09/2018 a las 21:26

  • Me encontré varias veces en las que verificamos que no se llamó a algo, luego cambiamos la implementación para llamar a otra cosa … y la prueba anterior aún pasa, porque el método anterior todavía no se llama, pero no verificamos el nuevo método. El patrón sugerido aquí ayudará a garantizar que su prueba siga siendo relevante: si actualiza el código sin actualizar una prueba, es posible que tenga problemas ocultos y asuma que su prueba todavía los cubre. Estoy de acuerdo con @DavidLavender: “Las otras respuestas aquí se basan en que el escritor de la prueba recuerde explícitamente enumerar estos controles: eso es demasiado propenso a errores en mi libro”.

    – aarowman

    25 de marzo de 2021 a las 21:26


avatar de usuario
fluir

Antes que nada: siempre debes importar mockito static, de esta manera el código será mucho más legible (e intuitivo):

import static org.mockito.Mockito.*;

En realidad, hay muchas maneras de lograr esto, sin embargo, es (posiblemente) más limpio usar el

verify(yourMock, times(0)).someMethod();

método en todas sus pruebas, cuando en otras pruebas lo usa para afirmar una cierta cantidad de ejecuciones como esta:

verify(yourMock, times(5)).someMethod();

Las alternativas son:

verify(yourMock, never()).someMethod();

Alternativamente, cuando realmente quiera asegurarse de que un determinado Objeto simulado NO se llame en absoluto, puede usar:

verifyZeroInteractions(yourMock)

Tenga en cuenta: verificarZeroInteractions(Object… simulacros) está en desuso. Desde la versión 3.0.1. El método recomendado ahora es:

verifyNoInteractions(yourMock)

avatar de usuario
Ujjwal

Ambos verifyNoMoreInteractions() y verifyZeroInteractions() El método internamente tiene la misma implementación que:

public static transient void verifyNoMoreInteractions(Object mocks[])
{
    MOCKITO_CORE.verifyNoMoreInteractions(mocks);
}

public static transient void verifyZeroInteractions(Object mocks[])
{
    MOCKITO_CORE.verifyNoMoreInteractions(mocks);
}

por lo que podemos usar cualquiera de ellos en un objeto simulado o una matriz de objetos simulados para verificar que no se haya llamado a ningún método usando objetos simulados.

  • Transitorio es para campos

    -Kartik Chugh

    21 de julio de 2020 a las 18:14

avatar de usuario
Alex Blasco

Solo como sugerencia, si desea estar más alineado a nivel de sintaxis con Desarrollo impulsado por el comportamiento estilo hay BDDMockito:

Podrías usar:

then(dependency).should(never()).someMethod();

Como reemplazo equivalente de:

verify(dependency, never()).someMethod();

  • Transitorio es para campos

    -Kartik Chugh

    21 de julio de 2020 a las 18:14

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad