web-dev-qa-db-fra.com

Mockito correspond à n'importe quel argument de classe

Existe-t-il un moyen de faire correspondre un argument de classe du sous-exemple de routine?

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

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

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

EDIT: Une solution est

(Class<?>) any(Class.class)
132
Johan Sjöberg

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

La première 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 la frappe exacte (le Class<? extends A>) mais cela fonctionne probablement comme vous en avez besoin.

La seconde est beaucoup plus complexe, mais constitue sans doute une meilleure solution si vous vraiment voulez être sûr que l'argument de 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éfini 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");
    }       
}

Phew! J'irais avec la première option jusqu'à ce que vous vraiment devez mieux contrôler ce que method() renvoie réellement :-)

170
millhouse

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

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

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

45
anmaia

Si vous ne savez pas quel paquet vous devez importer:

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

OR

import org.mockito.Matchers;
Matchers.any(SomeClass.class)
35
Joao Luiz Cadore

Que diriez-vous:

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

ou:

when(a.method((A)notNull())).thenReturn(b);
23
Tomasz Nurkiewicz

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 une instance de 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);
8
Bertrand Cedric