Mockito匹配任何类参数


153

有没有办法匹配以下示例例程的任何类参数?

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

无论传递到哪个类,如何始终返回a ?以下尝试仅适用于匹配的特定情况。new B()methodA

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

编辑:一种解决方案是

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

6
Class<?>惊人!
安东尼奥·阿尔梅达

您的(Class <?>)any(Class.class)解决方案应该是这里的答案。我宁愿使用它,然后使用下面显示的ClassOrSubclassMatcher类。
superbAfterSemperPhi 2015年

@superbAfterSemperPhi和johan-sjöberg我发布了另一种方法,无需强制转换。我相信这可能是更好的方法。你怎么看?
anmaia '16

Answers:


188

还有两种方法(请参阅我对@Tomasz Nurkiewicz的先前回答的评论):

第一个依据的事实是编译器根本不允许您传递错误的类型:

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

您会丢失准确的输入(Class<? extends A>),但可能会按需要使用。

第二个涉及更多,但如果您确实要确保to的参数method()是的A或的子类,则可以说是更好的解决方案A

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

其中ClassOrSubclassMatcherorg.hamcrest.BaseMatcher定义为:

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

!我会选择第一个选项,直到您真正需要更好地控制method()实际返回的内容为止:-)


if (obj instanceof Class)混乱的事情了我,所以我删除它。
丹尼尔·史密斯

在该类的声明行上,我不得不更改extends BaseMatcher<Class<T>>为just extends BaseMatcher<T>。仅供参考,如果其他人遇到编译错误,请尝试一下。
1

我还必须将matches函数更改为以下内容:public boolean matches(Object obj) { if (obj != null) { return targetClass.isAssignableFrom(obj.getClass()); } return false; }
1

any(Class.class)返回null-我如何避免返回null
Arvind Kumar

如果实际上添加我需要导入的类,那将是很好的,因为现在有很多来自
模仿者的

53

还有一种不用强制转换的方法:

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

此解决方案强制该方法any()返回Class<A>类型,而不是其默认值(Object)。


5
Matchers在较新版本的Mockito中已弃用,很可能在3.0版中将其删除。使用ArgumentMatchers来代替:when(a.method(ArgumentMatchers.<Class<A>>any())).thenReturn(b);
沃伊库

41

如果您不知道需要导入哪个软件包:

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

要么

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

13
这挽救了我的生命,我不小心从hamcrest库中导入了“ any”。
加博·纳吉

3
现在它已更改为org.mockito.ArgumentMatchers.any
BOWS

27

怎么样:

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

要么:

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

4
如果方法签名是method(A a)-但实际上是有效的,则这些代码可以编译并工作method(Class<A> a),因此您需要使用:when(a.method(isA(Class.class))).thenReturn(b);when(a.method((Class<A>) notNull())).thenReturn(b);
millhouse 2011年

对我来说第二部分是魅力。与any(SomeClass.class)的争斗导致死胡同。但是(SomeClass.class)notNull()挽救了我的一天
Vadim

如果您有两个名称相同但参数不同的方法,则可以在此处使用第二种方法消除要模拟的方法的歧义。第一个版本没有对我有用(在Java 8上)。
Patru

谢谢,isA(A.class)对我有用,并且mvcConversionService选择正确的类。这不适用于any(A.class)和eq(A.class)。
d3rbastl3r

9

Millhouse的解决方案在最新版本的mockito中不再起作用

此解决方案适用于Java 8和Mockito 2.2.9

ArgumentMatcher实例的位置在哪里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;
    }
}

和使用

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

instanceof条件不再需要了,我写了一种便捷的方法:public static <T> Class<T> subClassOf(Class<T> targetClass) { return argThat(new ClassOrSubclassMatcher<>(targetClass)); }
Daniel Alder
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.