Mockito coincide con cualquier argumento de clase


153

¿Hay alguna manera de hacer coincidir algún argumento de clase de la rutina de muestra a continuación?

class A {
     public B method(Class<? extends A> a) {}
}

¿Cómo puedo devolver siempre un new B()independientemente de en qué clase se pasa method? El siguiente intento solo funciona para el caso específico donde Acoincide.

A a = new A();
B b = new B();
when(a.method(eq(A.class))).thenReturn(b);

EDITAR : Una solución es

(Class<?>) any(Class.class)

66
Class<?>¡asombroso!
António Almeida

Su (Clase <?>) Cualquier solución (Clase.clase) debería ser la respuesta aquí. Prefiero usar eso que la clase ClassOrSubclassMatcher que se ve a continuación.
superbAfterSemperPhi

@superbAfterSemperPhi y johan-sjöberg Publiqué otra forma de hacerlo, sin elenco. Creo que podría ser una mejor manera. ¿Qué piensas?
anmaia

Respuestas:


188

Dos formas más de hacerlo (vea mi comentario sobre la respuesta anterior de @Tomasz Nurkiewicz):

El primero se basa en el hecho de que el compilador simplemente no le permitirá pasar algo del tipo incorrecto:

when(a.method(any(Class.class))).thenReturn(b);

Pierde el tipeo exacto (el Class<? extends A>) pero probablemente funcione como lo necesita.

El segundo es mucho más complicado, pero podría decirse que es una mejor solución si realmente quieres estar seguro de que el argumento method()es una Ao una subclase de A:

when(a.method(Matchers.argThat(new ClassOrSubclassMatcher<A>(A.class)))).thenReturn(b);

Donde ClassOrSubclassMatcherse org.hamcrest.BaseMatcherdefine como:

public class ClassOrSubclassMatcher<T> extends BaseMatcher<Class<T>> {

    private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @SuppressWarnings("unchecked")
    public boolean matches(Object obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom((Class<T>) obj);
            }
        }
        return false;
    }

    public void describeTo(Description desc) {
        desc.appendText("Matches a class or subclass");
    }       
}

¡Uf! Iría con la primera opción hasta que realmente necesites tener un control más preciso sobre lo que method()realmente regresa :-)


me if (obj instanceof Class)arruina las cosas, así que lo eliminé.
Daniel Smith

En la línea de declaración de la clase, tuve que cambiar extends BaseMatcher<Class<T>>a justo extends BaseMatcher<T>. Solo para tu información, si alguien más obtiene errores de compilación, pruébalo.
Jan

También tuve que cambiar la matchesfunción a la siguiente:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
Jan

any (Class.class) está volviendo nulo - ¿cómo puedo evitar volver nulo?
Arvind Kumar

sería genial si realmente agrego la clase que necesito importar ya que ahora hay muchos "cualquiera" de mockito
jpganz18

53

Hay otra forma de hacerlo sin yeso:

when(a.method(Matchers.<Class<A>>any())).thenReturn(b);

Esta solución obliga al método any()a devolver el Class<A>tipo y no su valor predeterminado ( Object).


55
Matchersestá en desuso en las versiones más recientes de Mockito y probablemente se eliminará en la versión 3.0. Utilice en su ArgumentMatcherslugar:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
Voicu

41

Si no tiene idea de qué paquete necesita importar:

import static org.mockito.ArgumentMatchers.any;
any(SomeClass.class)

O

import org.mockito.ArgumentMatchers;
ArgumentMatchers.any(SomeClass.class)

13
Esto me salvó la vida, estaba importando accidentalmente "cualquiera" de la biblioteca Hamcrest.
Gábor Nagy

3
Ahora ha cambiado aorg.mockito.ArgumentMatchers.any
BOWS

27

Qué tal si:

when(a.method(isA(A.class))).thenReturn(b);

o:

when(a.method((A)notNull())).thenReturn(b);

44
Estos se compilarían y funcionarían si la firma del método fuera method(A a), pero es (efectivamente) method(Class<A> a), por lo que necesitaría usar: when(a.method(isA(Class.class))).thenReturn(b);owhen(a.method((Class<A>) notNull())).thenReturn(b);
millhouse

La segunda parte para mí funciona como encanto. pelear con cualquier (SomeClass.class) conducir a un callejón sin salida. Pero (SomeClass.class) notNull () me salvó el día
Vadim

Si tiene dos métodos con el mismo nombre pero con argumentos diferentes, puede desambiguar el método que se burlará usando la segunda versión aquí. La primera versión no fue suficiente para mí (en Java 8).
Patru

Gracias, isA (A.class) funciona bien para mí y el mvcConversionService selecciona la clase correcta. Esto no funcionaba con ninguna (A.class) y eq (A.class).
d3rbastl3r

9

la solución de millhouse ya no funciona con la versión reciente de mockito

Esta solución funciona con Java 8 y Mockito 2.2.9

donde ArgumentMatcheres una instancia deorg.mockito.ArgumentMatcher

public class ClassOrSubclassMatcher<T> implements ArgumentMatcher<Class<T>> {

   private final Class<T> targetClass;

    public ClassOrSubclassMatcher(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    @Override
    public boolean matches(Class<T> obj) {
        if (obj != null) {
            if (obj instanceof Class) {
                return targetClass.isAssignableFrom( obj);
            }
        }
        return false;
    }
}

Y el uso

when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);

la instancia de condición ya no es necesaria, y escribí un método de conveniencia:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.