Mockito: InvalidUseOfMatchersException

141

Tengo una herramienta de línea de comandos que realiza una verificación de DNS. Si la comprobación de DNS tiene éxito, el comando continúa con otras tareas. Estoy tratando de escribir pruebas unitarias para esto usando Mockito. Aquí está mi código:

public class Command() {
    // ....
    void runCommand() {
        // ..
        dnsCheck(hostname, new InetAddressFactory());
        // ..
        // do other stuff after dnsCheck
    }

    void dnsCheck(String hostname, InetAddressFactory factory) {
        // calls to verify hostname
    }
}

Estoy usando InetAddressFactory para burlarse de una implementación estática de la InetAddressclase. Aquí está el código para la fábrica:

public class InetAddressFactory {
    public InetAddress getByName(String host) throws UnknownHostException {
        return InetAddress.getByName(host);
    }
}

Aquí está mi caso de prueba de unidad:

@RunWith(MockitoJUnitRunner.class)
public class CmdTest {

    // many functional tests for dnsCheck

    // here's the piece of code that is failing
    // in this test I want to test the rest of the code (i.e. after dnsCheck)
    @Test
    void testPostDnsCheck() {
        final Cmd cmd = spy(new Cmd());

        // this line does not work, and it throws the exception below:
        // tried using (InetAddressFactory) anyObject()
        doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class));
        cmd.runCommand();
    }
}

Excepción al ejecutar la testPostDnsCheck()prueba:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
2 matchers expected, 1 recorded.
This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

¿Alguna aportación sobre cómo resolver esto?

devang
fuente

Respuestas:

283

El mensaje de error describe la solución. La línea

doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class))

usa un valor sin procesar y un emparejador, cuando se requiere usar todos los valores en bruto o todos los emparejadores. Una versión correcta podría leer

doNothing().when(cmd).dnsCheck(eq(HOST), any(InetAddressFactory.class))
Ryan Stewart
fuente
8
Que tonto de mi parte. Seguí analizando por qué el segundo parámetro seguía dándome el error. Gracias por aclararlo. Soy muy nuevo en Mockito, este es mi primer encuentro.
devang
32

Tuve el mismo problema durante mucho tiempo, a menudo necesitaba mezclar Matchers y valores y nunca pude hacerlo con Mockito ... ¡hasta hace poco! Puse la solución aquí esperando que ayude a alguien, incluso si esta publicación es bastante antigua.

Claramente, no es posible usar Matchers AND valores juntos en Mockito, pero ¿qué pasa si un Matcher acepta comparar una variable? Eso resolvería el problema ... y de hecho hay: eq

when(recommendedAccessor.searchRecommendedHolidaysProduct(eq(metas), any(List.class), any(HotelsBoardBasisType.class), any(Config.class)))
            .thenReturn(recommendedResults);

En este ejemplo, 'metas' es una lista de valores existente

sam
fuente
55
Increíble. org.mockito.Mockito.eq()
javaPlease42
44
la importación adecuada ahora es org.mockito.ArgumentMatchers.eq ()
sam
15

Podría ayudar a alguien en el futuro: Mockito no admite la burla de los métodos 'finales' (en este momento). Me dio lo mismo InvalidUseOfMatchersException.

La solución para mí fue poner la parte del método que no tenía que ser 'final' en un método separado, accesible y reemplazable.

Revise la API de Mockito para su caso de uso.

delucasvb
fuente
Esto ayudó a descubrir por qué mi código de Kotlin me daría un error, ¡porque todos los métodos en Kotlin son finales!
sorry_I_wont el
0

A pesar de usar todos los comparadores, recibía el mismo problema:

"org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
1 matchers expected, 3 recorded:"

Me tomó poco tiempo darme cuenta de que el método que intentaba burlarme era un método estático de una clase (digamos Xyz.class) que contiene solo un método estático y olvidé escribir la siguiente línea:

PowerMockito.mockStatic(Xyz.class);

Puede ser que ayude a otros, ya que también puede ser la causa del problema.

S Kumar
fuente
0

Para mi caso, la excepción surgió porque traté de burlarme de un package-accessmétodo. Cuando cambié el método, el nivel de acceso packagea protectedla excepción desapareció. Por ejemplo, debajo de la clase Java,

public class Foo {
    String getName(String id) {
        return mMap.get(id);
    }
}

el método String getName(String id)tiene que estar AL MENOS protected para que el mecanismo de burla (subclasificación) pueda funcionar.

shizhen
fuente