Mockito corrisponde a qualsiasi argomento di classe


153

C'è un modo per abbinare qualsiasi argomento di classe della routine di esempio di seguito?

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

Come posso sempre restituire un new B()indipendentemente da quale classe è passata method? Il seguente tentativo funziona solo per il caso specifico in cui Aè associato.

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

EDIT : una soluzione è

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

6
Class<?>sorprendente!
António Almeida,

La soluzione (Class <?>) Qualsiasi (Class.class) dovrebbe essere la risposta qui. Preferirei di gran lunga usare quella classe ClassOrSubclassMatcher vista di seguito.
superbAfterSemperPhi,

@superbAfterSemperPhi e johan-sjöberg ho pubblicato un altro modo per farlo, senza cast. Credo che potrebbe essere un modo migliore. Cosa ne pensi?
anmaia,

Risposte:


188

Altri due modi per farlo (vedi il mio commento sulla risposta precedente di @Tomasz Nurkiewicz):

Il primo si basa sul fatto che il compilatore semplicemente non ti lascerà passare qualcosa del tipo sbagliato:

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

Si perde la digitazione esatta (il Class<? extends A>) ma probabilmente funziona come è necessario.

Il secondo è molto più coinvolto, ma è probabilmente una soluzione migliore per te davvero essere sicuro che l'argomento method()sia una Ao una sottoclasse di A:

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

Dove ClassOrSubclassMatcherè org.hamcrest.BaseMatcherdefinito come:

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");
    }       
}

Accidenti! Andrei con la prima opzione fino a quando davvero bisogno di ottenere un controllo più preciso su ciò che method()effettivamente restituisce :-)


le if (obj instanceof Class)cose vanno male per me, quindi l'ho rimosso.
Daniel Smith,

Sulla riga di dichiarazione della classe, ho dovuto passare extends BaseMatcher<Class<T>>a just extends BaseMatcher<T>. Cordiali saluti, se qualcun altro riceve errori di compilazione, provalo.
Jan

Ho anche dovuto modificare la matchesfunzione come segue:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
Jan

any (Class.class) restituisce null - come posso evitare di restituire null
Arvind Kumar

sarebbe fantastico se effettivamente aggiungessi la classe che devo importare dato che ora ci sono molti "qualsiasi" da mockito
jpganz18

53

C'è un altro modo per farlo senza cast:

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

Questa soluzione impone al metodo any()di restituire il Class<A>tipo e non il suo valore predefinito ( Object).


5
Matchersè obsoleto nelle versioni più recenti di Mockito e verrà probabilmente rimosso nella versione 3.0. Utilizzare ArgumentMatchersinvece:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
Voicu

41

Se non hai idea di quale pacchetto devi importare:

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

O

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

13
Questo mi ha salvato la vita, importando accidentalmente "qualsiasi" dalla libreria più amara.
Gábor Nagy,

3
Ora è cambiato inorg.mockito.ArgumentMatchers.any
BOWS il

27

Che ne dite di:

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

o:

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

4
Compilerebbero e funzionerebbero se la firma del metodo fosse method(A a)- ma è (efficacemente) method(Class<A> a)- quindi avresti bisogno di usare: when(a.method(isA(Class.class))).thenReturn(b);oppurewhen(a.method((Class<A>) notNull())).thenReturn(b);
Millhouse

la seconda parte per me funziona come un incantesimo. combattere con qualsiasi (SomeClass.class) portare a un vicolo cieco. Ma (SomeClass.class) notNull () mi ha salvato la giornata
Vadim il

Se hai due metodi con lo stesso nome ma argomenti diversi, puoi disambiguare il metodo da deridere usando la seconda versione qui. La prima versione non l'ha tagliata per me (su Java 8 cioè).
Patru,

Grazie, isA (A.class) funziona perfettamente per me e mvcConversionService seleziona la classe giusta. Questo non funzionava con alcun (A.class) ed eq (A.class).
d3rbastl3r

9

la soluzione di Millhouse non funziona più con la versione recente di mockito

Questa soluzione funziona con java 8 e mockito 2.2.9

dove ArgumentMatcherè un'istanza diorg.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;
    }
}

E l'uso

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

la condizione di instanceof non è più necessaria e ho scritto un metodo di praticità:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.