为什么在模拟TextView时会出现InvalidUseOfMatchersException?

时间:2015-09-16 18:50:38

标签: java android unit-testing textview mockito

我有一组测试来验证Android应用中的某些功能。部分代码负责将某些字符串放入某些TextView中。所以我想在测试时创建模拟的TextView对象:

public static TextView getMockTextView() {
    TextView view = mock(TextView.class);
    final MutableObject<CharSequence> text = new MutableObject<CharSequence>();
    doAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            text.value = (CharSequence) invocation.getArguments()[0];
            return null;
        }
    }).when(view).setText((CharSequence) any());
    when(view.getText()).thenReturn(text.value);
    return view;
}

这适用于2参数setText(CharSequence, BufferType) ...但是,我们的大多数代码只调用setText(CharSequence)所以我想在那种情况下捕获字符串(正如你在上面的代码)。

但我得到了这个例外:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.me.util.MockViewHelper.getMockTextView(MockViewHelper.java:49)

This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

我尝试了CharSequence)any()(CharSequence)anyObject(),甚至是anyString()eq("")只是为了看看它是否有用而且Mockito仍然不喜欢我试图告诉它如何在setText()的单参数版本中做什么。

有什么想法在这里发生了什么?

1 个答案:

答案 0 :(得分:1)

来自the TextView docs

  

public final void setText(CharSequence text)

Mockito can't mock final methods; Mockito生成的mock / spy类实际上是一个Proxy,但因为setText(CharSequence)是最终的,JVM假定它知道要调用哪个实现(TextView的实际实现)并且不会将代理(Mockito实现)作为虚拟方法调度将决定。据推测,setText(CharSequence)的实现实际上调用了setText(CharSequence, BufferType),Mockito假定这是你想要模拟的调用,因此它会给出错误消息“2匹配预期,1记录”。 (第二个匹配器将用于BufferType。)

您需要执行以下操作之一:

  • 使用Robolectric,它使用特殊的类加载器将Android类替换为测试中可行的等效项。
  • 使用PowerMock,它还使用特殊的类加载器来重写被测系统,即使在调用最终方法时也会委托给模拟器(以及许多其他添加的功能)。
  • 完全使用模拟,并使用真实对象或编写完全可模拟的包装层。