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)
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);
Où 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 : -)
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
).
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)
Que diriez-vous de:
when(a.method(isA(A.class))).thenReturn(b);
Ou:
when(a.method((A)notNull())).thenReturn(b);
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
Où 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);