问题描述
当存根 ClassOne.methodOne
时,我收到以下关于存根具有返回值的 void 方法的错误消息,即使 ClassOne.methodOne
不是 void.该错误似乎与 ClassTwo.methodTwo
相关,即使我正在对 ClassOne.methodOne
进行存根.
When stubbing ClassOne.methodOne
, I'm getting the following error message about stubbing a void method with a return value, even though ClassOne.methodOne
is not void. The error seems to pertain to ClassTwo.methodTwo
, even though I'm stubbing ClassOne.methodOne
.
org.mockito.exceptions.base.MockitoException:
`'methodTwo'` is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is *overloaded*. Make sure you are calling
the right overloaded version.
2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not
verify/stub final methods.
3. A spy is stubbed using `when(spy.foo()).then()` syntax. It is safer to stub
spies with `doReturn|Throw()` family of methods. More in javadocs for
Mockito.spy() method.
我的代码:
public class ClassOne {
private ClassTwo classTwo;
public boolean methodOne() {
classTwo.methodTwo();
return true;
}
}
我的测试:
when(classOne.methodOne("some string")).thenReturn(true);
为什么会发生这种情况,我该如何解决?
Why is this happening, and how do I fix it?
推荐答案
当您尝试存根 Mockito 无法覆盖的方法时,可能会发生这种情况. when 的语法方式code> 有效,Mockito 将它可以检测到的最近调用识别为对 stub 的方法调用.如果 Mockito 无法检测到您正在存根的方法调用,但可以检测到在存根方法的实际实现中发生的模拟上的调用,那么它可能会将该调用误认为是存根调用.因此,它认为您正在使用返回值存根 void 方法
ClassTwo.methodTwo
,并抛出异常.
This can happen when you try to stub a method that Mockito cannot override. The way the syntax for when
works, Mockito identifies the most recent call it can detect as the method call to stub. If Mockito cannot detect the method call you're stubbing, but can detect a call on a mock that happens within the actual implementation of the stubbed method, then it may mistake that call as the stubbing call. Thus, it thinks you are stubbing void method ClassTwo.methodTwo
with a return value, and throws the exception.
/* 1 */ when(classOne.methodOne("some string")).thenReturn(true);
/* 2 */ when( false ).thenReturn(true);
/* 3 */ ( internal mockito stub object ).thenReturn(true);
通常,Mockito 调用 classOne.methodOne
,这是一个模拟上的非存根方法.Mockito 的默认实现检测调用,将调用记录为最后接收到的调用,并返回 false.然后,在上面的第 2 步中,Mockito 看到对 when
的调用,将最后一次调用标记为存根,并准备对 thenVerb
的调用,这在第 3 步中出现. 但是,在这种情况下,在第一步中,Mockito 没有覆盖methodOne
,因此它无法检测到调用或记录调用.它实际上调用了 classOne.methodOne
,如果有任何与模拟的交互,这些交互会被记录下来,就好像它们在 when
调用上方的测试中一样.步骤 2 与之前一样进行,只是 Mockito 标记了对存根的错误调用,因此步骤 3 看到对 void 方法的 thenReturn
调用.
Normally, Mockito calls classOne.methodOne
, which is an unstubbed method on a mock. Mockito's default implementation detects the call, records the invocation as the last-received invocation, and returns false. Then, in step 2 above, Mockito sees the call to when
, marks that last invocation as a stub instead, and prepares for a call to thenVerb
, which comes in step 3. However, in this case, during step one, Mockito hasn't overridden methodOne
, so it can't detect the call or record the invocation. It actually calls classOne.methodOne
, and if there are any interactions with a mock, those get recorded instead as if they were in the test above the when
call. Step 2 proceeds as before, except that Mockito marks the wrong call for the stub, so step 3 sees a call to thenReturn
for the void method.
如果您使用匹配器,这会更加麻烦,因为如果内部匹配器堆栈上的匹配器数量错误
This can be even more troublesome if you use Matchers, because if there are the wrong number of Matchers on the internal matcher stack, then you may get an InvalidUseOfMatchersException, even if the stubbing call in the test appears to use matchers correctly.
当 Mockito 无法覆盖您存根的方法时,就会出现这个问题.您需要检查以下内容是否全部正确:
This problem crops up when Mockito cannot override the method you're stubbing. You'll need to check that the following is all true:
- 该类应该是非
final
,并且不应具有非公共
父母. - 方法应该是非
static
和非final
. - 实例应该是一个 Mockito 模拟.注意,如果它是用
@InjectMocks
创建的,它是一个真正的实现而不是一个模拟;在此处阅读更多信息. - 如例外中所述,当存根间谍时,使用
doReturn
/doAnswer
/doThrow
语法,否则你将在对 .
- The class should be non-
final
, and should not have non-public
parents. - The method should be non-
static
and non-final
. - The instance should be a Mockito mock. Note that if it is created with
@InjectMocks
, it is a real implementation and not a mock; read more here. - As mentioned in the exception, when stubbing a spy, use
doReturn
/doAnswer
/doThrow
syntax, because otherwise you will call the spy's actual method from within the call towhen
.
这篇关于错误:不能用返回值存根 *不同的* void 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!