无法在验证参数中使用模拟函数调用:调用过多 [英] Cannot use mocked function calls in parameters of verify: too many invocations

查看:98
本文介绍了无法在验证参数中使用模拟函数调用:调用过多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

设置如下:

//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(这里的重点:不是doB!),并且希望只打一次它!

Obviously, doA() is configured to return some value, and mockedThing is indeed mocked. The result is: mockito complains that I call doA (Emphasis here: NOT doB!) too often, and that it expected it to be called only once!

以下更改有效:

int result = mockedThing.doA() 
verify(mockedThing).doB(eq(result));

我的问题很简单:这是怎么回事?为什么Mockito会验证对传递给函数的 parameters 的调用,而不是对函数本身的调用?

My question is simple: what is going on here? Why is Mockito verifying the call to the parameters I pass to the function rather than the calls to the function itself?

推荐答案

正如我的评论中所述,Mockito实际上以不直观的方式是有状态的.很多时候,存根或验证的方法仅仅是最后调用的方法",主要是因为verify(foo).doA()之类的语法实际上调用了doA而不是将对方法doA的反射引用传递给Mockito.这完全与在存根或验证过程中调用同一模拟程序的语法不兼容.

As mentioned in my comment, Mockito is actually stateful in unintuitive ways; many times the method stubbed or verified is simply the "last called method", mostly because syntax like verify(foo).doA() actually calls doA rather than passing a reflective reference to the method doA into Mockito. This simply isn't compatible with syntax that calls the same mock in the middle of stubbing or verification.

我之前就匹配器写过这个问题,在存根过程中也遇到了同样的问题.遍历源代码,至少在同一个模拟上调用方法时,您会看到相同的验证问题.

I've written about this before with regard to Matchers, which have the same problem during stubbing. Poking through the source code, you can see the same problem with verification, at least when calling a method on the same mock.

简而言之,验证实际上是一个三个阶段的过程:

In short, verification is actually a three phase process:

  1. 致电verify(mockedThing).
  2. 如有必要,请按顺序致电匹配器.不要在mockedThing上调用任何方法.
  3. 调用mockedThing上要验证的方法,如果不使用匹配器,则使用实际参数值,如果使用匹配器,则使用虚拟(忽略)参数值.由于Mockito在后台跟踪匹配器堆栈,因此Matcher方法可以返回0null,而Mockito不会认为这些值是要检查的值.
  1. Call verify(mockedThing).
  2. Call matchers, in order, if necessary. Do not call any methods on mockedThing.
  3. Call the method that you're verifying on mockedThing, with actual parameter values if you're not using matchers, and dummy (ignored) parameter values if you are using matchers. Since Mockito keeps track of the matchers stack in the background, matcher methods can return 0 or null without Mockito thinking those are values to check against.

在封面下

调用然后,在处理所有模拟调用的 handler ,Mockito会在验证开始后对模拟的首次调用中开始验证:

Then, inside the handler that handles all mock invocations, Mockito starts verification on the first call to the mock that happens once verification is started:

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()));和额外的eq(5),您将收到有关滥用匹配器的不同错误消息-特别是因为Mockito不仅认为您正在验证doA,而且您以某种方式认为doA接受了争论.

Therefore, if you interact with the mock just to get a parameter value, Mockito is going to assume that you're actually calling the method to verify. Note that if the call was slightly different, like verify(mockedThing).doB(eq(5), eq(mockedThing.doA())); with the extra eq(5), you'd get a different error message about misusing matchers—specifically because Mockito doesn't just think you're verifying doA, but that you somehow think doA takes an argument.

您的代码无效:

// DOESN'T WORK
verify(mockedThing).doB(eq(mockedThing.doA()));
// BECAUSE IT BEHAVES THE SAME AS
verify(mockedThing).doA();

但是将其提取确实有效:

But extracting it does work:

// WORKS, though it makes an extra call to doA
Value value = mockedThing.doA();
verify(mockedThing).doB(eq(value));

这也行得通,并显示了幕后发生的事情,但切勿在真实的测试中编写此内容:

And this also works, and shows off what's happening under the covers, but don't ever write this in a real test:

// 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 */);

这篇关于无法在验证参数中使用模拟函数调用:调用过多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆