Mockito correspond à n'importe quel argument de classe

Existe-t-il un moyen de faire correspondre un argument de classe de l'exemple de routine ci-dessous?

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

Comment puis-je toujours retourner un new B() quelle que soit la classe passée dans method? La tentative suivante ne fonctionne que pour le cas spécifique où A est mis en correspondance.

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

EDIT: Une solution est

(Class<?>) any(Class.class)
110
demandé sur Johan Sjöberg 2011-09-21 17:09:58

5 réponses

Deux autres façons de le faire (voir mon commentaire sur la réponse précédente de @ Tomasz Nurkiewicz):

Le premier repose sur le fait que le compilateur ne vous laissera tout simplement pas passer quelque chose du mauvais type:

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

Vous perdez le typage exact (le Class<? extends A>) mais cela fonctionne probablement comme vous en avez besoin.

, Le second est beaucoup plus complexe, mais il est sans doute une meilleure solution si vous avez vraiment voulez être sûr que l'argument method() est un A, ou une sous-classe de A:

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

ClassOrSubclassMatcher est un org.hamcrest.BaseMatcher définie comme:

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

Ouf! J'irais avec la première option jusqu'à ce que vraiment besoin d'obtenir un contrôle plus fin sur ce que method() retourne réellement : -)

150
répondu millhouse 2011-10-07 04:06:51

Il y a une autre façon de le faire sans lancer:

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

Cette solution force la méthode any() à renvoyer le type Class<A> et non sa valeur par défaut (Object).

34
répondu anmaia 2016-01-12 20:07:43

Si vous n'avez aucune idée du paquet que vous devez importer:

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

Ou

import org.mockito.Matchers;
Matchers.any(SomeClass.class)
26
répondu Joao Luiz Cadore 2016-04-06 03:09:11

Que diriez-vous de:

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

Ou:

when(a.method((A)notNull())).thenReturn(b);
19
répondu Tomasz Nurkiewicz 2011-09-21 13:15:05

La solution de millhouse ne fonctionne plus avec la version récente de mockito

Cette solution fonctionne avec java 8 et mockito 2.2.9

ArgumentMatcher est un instanceof org.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;
    }
}

Et l'utilisation

when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);
6
répondu Bertrand Cedric 2017-08-04 07:21:53