设置如下:
//call doA a bunch of times, call doB once using some value that depends on doA() verify(mockedThing).doB(eq(mockedThing.doA())); //removing eq() changes nothing
显然,它doA()被配置为返回一些值,并且mockedThing确实是被嘲笑的。结果是:mockito抱怨我经常打给我doA(强调:NOT doB!),并且希望只打一次它!
doA()
mockedThing
doA
doB
以下更改有效:
int result = mockedThing.doA() verify(mockedThing).doB(eq(result));
我的问题很简单:这是怎么回事?为什么Mockito会验证对传递给函数的 参数 的调用,而不是对函数本身的调用?
正如我在评论中提到的那样,Mockito实际上以不直观的方式处于有状态状态。很多时候,存根或验证的方法仅仅是“最后调用的方法”,主要是因为像这样的语法verify(foo).doA()实际上是在调用doA而不是将对方法的反射引用传递给doAMockito。这根本与在存根或验证过程中调用同一模拟程序的语法不兼容。
verify(foo).doA()
我之前已经针对Matchers撰写过有关此文章的文章,在存根期间也有同样的问题。遍历源代码,至少在同一个模拟中调用方法时,您会看到相同的验证问题。
简而言之,验证实际上是一个三个阶段的过程:
verify(mockedThing)
0
null
调用verify实际上只是设置一个标志并返回完全相同的模拟:
verify
public <T> T verify(T mock, VerificationMode mode) { // [catch errors] mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, mode)); return mock; }
然后,在处理所有模拟调用的 处理程序 内部,Mockito在对一旦开始验证的模拟的第一次调用中开始验证:
public Object handle(Invocation invocation) throws Throwable { // [detect doAnswer stubbing] VerificationMode verificationMode = mockingProgress.pullVerificationMode(); // [check Matcher state] // if verificationMode is not null then someone is doing verify() if (verificationMode != null) { // We need to check if verification was started on the correct mock // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138) if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) { VerificationDataImpl data = createVerificationData(invocationContainerImpl, invocationMatcher); verificationMode.verify(data); return null; } else { // this means there is an invocation on a different mock. Re-adding verification mode // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138) mockingProgress.verificationStarted(verificationMode); } } // [prepare invocation for stubbing] }
因此,如果您仅与模拟进行交互以获取参数值,则Mockito将假定您实际上是在调用方法进行验证。请注意,如果调用稍有不同(如verify(mockedThing).doB(eq(5),eq(mockedThing.doA()));extra一样)eq(5),您将收到有关滥用匹配器的不同错误消息-特别是因为Mockito不仅认为您正在验证doA,还以某种方式认为doA需要一个参数。
verify(mockedThing).doB(eq(5),eq(mockedThing.doA()));
eq(5)
您的代码无效:
// DOESN'T WORK verify(mockedThing).doB(eq(mockedThing.doA())); // BECAUSE IT BEHAVES THE SAME AS verify(mockedThing).doA();
但是提取它确实可以:
// WORKS, though it makes an extra call to doA Value value = mockedThing.doA(); verify(mockedThing).doB(eq(value));
而且这也有效,并显示了幕后发生的事情, 但是永远不要在真实的测试中编写 :
// WORKS BUT DON'T EVER ACTUALLY DO THIS Value value = mockedThing.doA(); verify(mockedThing); eq(value); mockedThing.doB(8675309 /* dummy value ignored because of matcher */);