4

我有一个类是Context. 我正在对另一个依赖于这个类的类进行单元测试,因此我嘲笑了它。但是,我需要一些方法来充当它们的原始行为,所以我要“取消模拟”它们。

其中之一是getAssets()我写了这个并且它工作正常:

Mockito.doReturn(this.getContext().getAssets()).when(keyboard).getAssets();

keyboard是提到的类的模拟实例。

由于此方法不带参数,因此覆盖它非常简单。

我也需要覆盖Context.getString(int)。该参数使事情变得困难,它是一个原始的,使事情变得更加困难。

我接受了这个建议和另一个建议,并尝试编写以下代码:

Mockito.when(keyboard.getString(Mockito.anyInt())).thenAnswer(new Answer<String>(){
    @Override
    public String answer(InvocationOnMock invocation) throws Throwable
         Integer arg = (Integer)invocation.getArguments()[0];
         return OuterClass.this.getContext().getString(arg.intValue());
    }
});

这编译并执行,但给出了以下异常:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at [...] <The code above>

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.

at android.content.Context.getString(Context.java:282)
at [...]
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:545)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551)

所以主要问题是如何覆盖 Mockito 中具有原始参数的方法?

提前致谢

4

3 回答 3

3

你不能存根getString,因为它是最终的。Mockito 不能存根 final 方法。只需保留它,你就会得到它的原始实现。这就是你想要的,对吧?

于 2013-09-22T09:52:09.317 回答
1

不应该是一个Answer<String>吗?

Mockito.when(keyboard.getString(Mockito.anyInt())).thenAnswer(new Answer<String>(){
    @Override
    public String answer(InvocationOnMock invocation) throws Throwable {
         return "foo";
    }
});

你可以重命名keyboard-->mockContext,这样会更清楚吗?

于 2013-09-22T08:47:37.247 回答
0

正如大卫华莱士他的回答中指出的那样,该Context.getString()方法是 final 的,我们知道 mockito 不能模拟 final 方法。所以覆盖它也是一个坏主意,并且不会起作用。

, 的"0 matchers expected, 1 recorded"描述信息InvalidUseOfMatchersException是一种模糊的说法,即该方法是final,我们不能试图覆盖它。

然而,让它保持原样也无济于事,因为该对象仍然是一个模拟对象,并且该方法不会显示我们希望从普通对象获得的预期行为;所以这个选项也不在讨论范围内。

最后我决定改变和改进我的设计。我使用了接口隔离原则Context并划分了和的职责Keyboard(我正在开发一个 IME 服务)。在应用程序本身中,我keyboard为这两个传递了相同的对象,但在测试中我模拟了Keyboard没有任何不良副作用的对象,并使用了TestCase.getContext()as,Context这消除了“取消模拟”其方法的需要。

于 2013-09-30T08:21:30.053 回答