我有一组测试来验证我们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参数版本中做什么。
你知道这是怎么回事吗?
From TextView docs:
public final void setText (CharSequence text)
Mockito不能模拟final方法;Mockito生成的mock/spy类实际上是一个代理,但是由于setText(CharSequence)
是final的,JVM假设它知道调用哪个实现(TextView的实际实现),并且不像虚拟方法调度所指示的那样咨询代理(Mockito实现)。假设setText(CharSequence)
的实现实际上调用了setText(CharSequence, BufferType)
, Mockito假设这是您想要模拟的调用,因此它会给您错误消息"预期2个匹配器,记录1个"。(第二个匹配器将用于BufferType。)
你需要做以下其中一项:
- 使用Robolectric,它使用一个特殊的类加载器在测试中用可工作的等效类替换Android类。
- 使用PowerMock,它还使用一个特殊的类加载器来重写被测系统,甚至在调用final方法时(以及许多其他添加的功能)也可以委托给mock。
- 完全跳过模拟,使用一个真实的对象或编写一个完全可模拟的包装层。