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)
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);
Où 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 :-)
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
).
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)
Que diriez-vous:
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 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);