¿Puede Mockito stub un método sin tener en cuenta el argumento?

4 minutos de lectura

avatar de usuario
eric wilson

Estoy tratando de probar un código heredado, usando Mockito.

quiero stub a FooDao que se utiliza en la producción de la siguiente manera:

foo = fooDao.getBar(new Bazoo());

Puedo escribir:

when(fooDao.getBar(new Bazoo())).thenReturn(myFoo);

Pero el problema obvio es que getBar() nunca se llama con el mismo Bazoo objeto para el que apagué el método. (Maldición que new ¡operador!)

Me encantaría si pudiera bloquear el método de una manera que devuelva myFoo independientemente del argumento. De lo contrario, escucharé otras sugerencias de solución, pero realmente me gustaría evitar cambiar el código de producción hasta que haya una cobertura de prueba razonable.

avatar de usuario
Tomasz Nurkiewicz

when(
  fooDao.getBar(
    any(Bazoo.class)
  )
).thenReturn(myFoo);

o (para evitar nulls):

when(
  fooDao.getBar(
    (Bazoo)notNull()
  )
).thenReturn(myFoo);

No olvides importar comparadores (muchos otros están disponibles):

Para Mockito 2.1.0 y posteriores:

import static org.mockito.ArgumentMatchers.*;

Para versiones anteriores:

import static org.mockito.Matchers.*;

  • Me encanta cuando la respuesta precede al final de ‘aceptar respuesta congelada’.

    –Eric Wilson

    11 mayo 2011 a las 19:50

  • Hay una notNull(Bazoo.class) al igual que el any(Bazoo.class) (tal vez no existía en el momento de esta respuesta)

    -Dandre Allison

    20 de febrero de 2013 a las 22:07

  • Tuve una situación un poco especial en la que podía tener cualquiera de dos argumentos posibles: Bazoo o Cazoo que son ambas subclases de, digamos, Azoo. por Bazoo necesitaba volver foopero para Cazoo necesitaba volver bar. en esta situación la propuesta Matchers.any() la solución no funciona, sin embargo, Matchers.isA() funciona perfecto

    – Tanvir

    15/04/2014 a las 14:57


  • org.mockito.Matchers ahora está en desuso – use org.mockito.ArgumentMatchers en cambio, es decir import static org.mockito.ArgumentMatchers.* (ver documentos)

    – No dividir por cero

    1 de noviembre de 2017 a las 13:38

  • when(myFoo.knowsWhatsUp()).thenReturn(myMoney);

    – 6rquídea

    29 de enero de 2019 a las 23:43


avatar de usuario
Buhb

http://site.mockito.org/mockito/docs/1.10.19/org/mockito/Matchers.html

anyObject() debe ajustarse a sus necesidades.

Además, siempre puede considerar implementar hashCode() y equals() Para el Bazoo clase. Esto haría que su ejemplo de código funcione de la manera que desea.

  • Estoy de acuerdo con la segunda sugerencia, pero sigo optando por no hacerlo por razones no técnicas.

    –Eric Wilson

    11 mayo 2011 a las 19:46

  • La clase Matchers está en desuso (ver documentos“Es probable que esta clase se elimine en la versión 3.0”)

    – Johannes Rabauer

    10 de octubre de 2019 a las 6:52

  • @JohannesRabauer Supongo que debería cambiarse a any() ?

    – golimar

    4 de mayo de 2021 a las 9:19

  • @golimar parece que esto hace exactamente lo mismo. any() y anyObject() son los mismos, de acuerdo con los documentos vinculados anteriormente. Sin embargo el completo Matchers la clase está en desuso y la clase ArgumentMatchers debe usarse en su lugar.

    – Johannes Rabauer

    13 de septiembre de 2021 a las 13:42

Usar así:

when(
  fooDao.getBar(
    Matchers.<Bazoo>any()
  )
).thenReturn(myFoo);

Antes de necesitar importar Mockito.Matchers

  • ¡Esto está en desuso!

    – DrB

    5 oct 2018 a las 15:36

avatar de usuario
José Martínez

Otra opción es confiar en la buena vieja moda equals método. Mientras el argumento en el when imitar equals el argumento en el código que se está probando, entonces Mockito coincidirá con el simulacro.

Aquí hay un ejemplo.

public class MyPojo {

    public MyPojo( String someField ) {
        this.someField = someField;
    }

    private String someField;

    @Override
    public boolean equals( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        MyPojo myPojo = ( MyPojo ) o;
        return someField.equals( myPojo.someField );
    }

}

entonces, suponiendo que sepa cuál es el valor de someField será, puedes burlarte así.

when(fooDao.getBar(new MyPojo(expectedSomeField))).thenReturn(myFoo);

pros: Esto es más explícito entonces any emparejadores Como revisor de código, mantengo un ojo abierto para any en el código que escriben los desarrolladores junior, mientras mira la lógica de su código para generar el objeto apropiado que se pasa.

contra: A veces, el campo que se pasa al objeto es una ID aleatoria. Para este caso, no puede construir fácilmente el objeto de argumento esperado en su código simulado.

Otro enfoque posible es usar Mockito’s Answer objeto que se puede utilizar con el when método. Answer le permite interceptar la llamada real e inspeccionar el argumento de entrada y devolver un objeto simulado. En el siguiente ejemplo estoy usando any para capturar cualquier solicitud al método que se burla. Pero luego en el Answer lambda, puedo inspeccionar más a fondo el argumento de Bazo… tal vez para verificar que se le pasó una identificación adecuada. prefiero esto a any por sí mismo para que al menos se realice alguna inspección en el argumento.

    Bar mockBar = //generate mock Bar.

    when(fooDao.getBar(any(Bazo.class))
    .thenAnswer(  ( InvocationOnMock invocationOnMock) -> {
        Bazo actualBazo = invocationOnMock.getArgument( 0 );

        //inspect the actualBazo here and thrw exception if it does not meet your testing requirements.
        return mockBar;
    } );

Entonces, para resumir todo, me gusta confiar en equals (donde el argumento esperado y el argumento real deben ser iguales entre sí) y si la igualdad no es posible (debido a que no puedo predecir el estado del argumento real), recurriré a Answer para inspeccionar el argumento.

¿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