Mockito. Verificar argumentos del método

7 minutos de lectura

avatar de usuario
manolowar

He buscado en Google sobre esto, pero no encontré nada relevante. Tengo algo como esto:

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj )).thenReturn(null);

Testeable testableObj = new Testeable();
testableObj.setMockeable(mock);
command.runtestmethod();

Ahora quiero comprobar que mymethod(Object o)que se llama dentro runtestmethod()fue llamado con el Objeto o, no cualquier otro. Pero siempre paso la prueba, ponga lo que ponga en la verificación, por ejemplo, con:

Mockito.verify(mock.mymethod(Mockito.eq(obj)));

o

Mockito.verify(mock.mymethod(Mockito.eq(null)));

o

Mockito.verify(mock.mymethod(Mockito.eq("something_else")));

Siempre paso la prueba. ¿Cómo puedo lograr esa verificación (si es posible)?

Gracias.

avatar de usuario
eugene82

una alternativa a ArgumentMatcher es ArgumentCaptor.

Ejemplo oficial:

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

Un captor también se puede definir usando el @Apresador anotación:

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}

  • ¡Gracias por la muestra! Nunca lo usé. Se siente un poco raro tener cosas como apresador en el código, pero ayudó.

    – Artemisa

    1 de marzo de 2016 a las 14:32

  • Jaja, no entendí la pregunta, pero la respuesta me ayudó mucho. Gracias 🙂

    – Marco K.

    14 de noviembre de 2017 a las 12:54

  • Importante: llamar a verificar()/capturar() después utilizando el simulacro. Estaba pensando que tiene que ser “instalado” antes…

    – Daniel Alder

    21 de febrero de 2018 a las 16:02

  • ¡Gracias por esta respuesta!

    – José Flavio Quispe Irrazábal

    12 de marzo de 2019 a las 21:08

  • ¡¡Esta es una respuesta genial!! ¡Muchos gracias!

    – Ulki Igor

    5 de junio de 2020 a las 9:01

avatar de usuario
epoxi

argThat más lambda

así es como puede fallar la verificación de su argumento:

    verify(mock).mymethod(argThat(
                            x -> false ));

dónde

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

argThat más afirma

la prueba anterior “dirá” Expected: lambda$... Was: YourClass.toSting.... Puede obtener una causa más específica de la falla si usa afirmaciones en la lambda:

    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));

❗️PERO❗️: ESTO SOLO FUNCIONA CUANDO

  • LA LLAMADA SE ESPERA 1 VEZ, o
  • la llamada se espera más de 2 veces, pero todas las veces el verificador coincide (devuelve true).

Si el método verificado llamó más de 2 veces, mockito pasa todas las combinaciones llamadas a cada verificador. Asi que mockito espera que tu verificador regrese silenciosamente true para uno de los conjuntos de argumentosy false (sin afirmar excepciones) para otras llamadas válidas. Esa expectativa no es un problema para 1 llamada de método; solo debería devolver verdadero 1 vez.

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

Ahora la prueba fallida dirá: Expected: Obj.description to contain 'KEY'. Was: 'Actual description'. NOTA: he usado assertJ afirma, pero depende de usted qué marco de afirmación usar.


argumento directo

Mokito compara argumentos directos usando equals():

verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.

eq emparejador


argThat con múltiples argumentos.

Si utiliza argThat, todos los argumentos debe estar provisto de fósforos. Por ejemplo, si, en otro caso, tenías otro método con 2 argumentos:

    verify(mock).mymethod2(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.

verify(mock).mymethod2("VALUE_1", argThat((x)->false));

// above is incorrect; an exception will be thrown, as the first arg. is given without an argument matcher.

dónde:

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

LA CAUSA RAÍZ del fracaso de la pregunta original era el lugar equivocado de los paréntesis:

  • verify(mock.mymethod.... Eso estuvo mal. El derecho sería:
  • verify(mock).*

  • Esta es mi respuesta favorita, funciona y es mucho más elegante que las demás.

    – Airwavezx

    4 de mayo de 2020 a las 13:17

  • ¿Cómo es este trabajo? verificar(simular).mimétodo(eq(“VALOR_1”), argEso((x)->falso)); “mymethod” tiene un argumento ¿cómo estamos enviando dos?

    – máx.

    28 de julio de 2021 a las 7:22

  • @max, captura correcta. El ejemplo estaba bajo … con múltiples argumentos sección, entonces, sí, tienes razón, no tiene relación con el original mymethod(arg0) caso. Solo tiene sentido para un caso diferente (2 argumentos). Cambiarle el nombre a mymethod2, para evitar la confusión, un poco.

    – epoxi

    28 de julio de 2021 a las 18:04

¿Está tratando de hacer una igualdad lógica utilizando el método .equals del objeto? Puede hacer esto utilizando el comparador argThat que se incluye en Mockito

import static org.mockito.Matchers.argThat

A continuación, puede implementar su propio comparador de argumentos que diferirá del método .equals de cada objeto

private class ObjectEqualityArgumentMatcher<T> extends ArgumentMatcher<T> {
    T thisObject;

    public ObjectEqualityArgumentMatcher(T thisObject) {
        this.thisObject = thisObject;
    }

    @Override
    public boolean matches(Object argument) {
        return thisObject.equals(argument);
    }
}

Ahora, usando su código, puede actualizarlo para que lea…

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj)).thenReturn(null);

Testeable obj = new Testeable();
obj.setMockeable(mock);
command.runtestmethod();

verify(mock).mymethod(argThat(new ObjectEqualityArgumentMatcher<Object>(obj)));

Si solo busca la igualdad EXACTA (el mismo objeto en la memoria), simplemente haga

verify(mock).mymethod(obj);

Esto verificará que fue llamado una vez.

  • Podrías usar la compilación ReflectionEquals clase para esos fines.

    – takacsot

    16 de abril de 2014 a las 6:23

  • +1 por tu respuesta. Pero me gustaría agregar que verify(mock).mymethod(obj); no verifica la igualdad EXACTA (mismo objeto en la memoria). En su lugar, utiliza el método de igualdad de objetos que podría haberse anulado.

    – eflujo

    20 mayo 2015 a las 18:32

  • También puede crear una implementación anónima de ArgumentMatcher ser menos prolijo.

    – botchniaque

    1 de septiembre de 2015 a las 13:07

  • Más detalle: por defecto verify() invoca el /argumento de entrada/ equals() método, en lugar del /objeto grabado/ equals() método. esto es irrelevante a menos que esté tratando de confirmar que su sujeto de prueba devuelve una instancia de objeto específica, y el sujeto devuelve lo que se supone que es un decorador transparente de esa instancia en su lugar. los verify argumento equals() no sabría del decorador; mientras que el decorador equals() sería reescrito para tolerar el original. En este caso, su prueba fallará falsamente.

    –Mark McKenna

    23 de junio de 2016 a las 18:24


  • no necesitas el eq matcher si no usa otros matchers.
  • No está utilizando la sintaxis correcta: la llamada a su método debe estar fuera del .verify(mock). Ahora está iniciando la verificación del resultado de la llamada al método, sin verificar nada (sin realizar una llamada al método). Por lo tanto, todas las pruebas están pasando.

Su código debe verse como:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");

He usado Mockito.verify de esta manera

@UnitTest
public class JUnitServiceTest
{
    @Mock
    private MyCustomService myCustomService;


    @Test
    public void testVerifyMethod()
    {
       Mockito.verify(myCustomService, Mockito.never()).mymethod(parameters); // method will never call (an alternative can be pick to use times(0))
       Mockito.verify(myCustomService, Mockito.times(2)).mymethod(parameters); // method will call for 2 times
       Mockito.verify(myCustomService, Mockito.atLeastOnce()).mymethod(parameters); // method will call atleast 1 time
       Mockito.verify(myCustomService, Mockito.atLeast(2)).mymethod(parameters); // method will call atleast 2 times
       Mockito.verify(myCustomService, Mockito.atMost(3)).mymethod(parameters); // method will call at most 3 times
       Mockito.verify(myCustomService, Mockito.only()).mymethod(parameters); //   no other method called except this
    }
}

avatar de usuario
bien

¿Has comprobado el método equals para la clase simulada? Si este devuelve siempre verdadero o prueba la misma instancia contra la misma instancia y el método igual no se sobrescribe (y por lo tanto solo verifica las referencias), entonces devuelve verdadero.

avatar de usuario
nils renaud

El otro método es usar el método org.mockito.internal.matchers.Equals.Equals en lugar de redefinir uno:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));

¿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