gpt4 book ai didi

java - 无法在验证 : too many invocations 的参数中使用模拟函数调用

转载 作者:行者123 更新时间:2023-11-30 06:09:57 27 4
gpt4 key购买 nike

设置如下:

//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!)太频繁了,而且它期望它只被调用一次!

以下更改有效:

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

我的问题很简单:这里发生了什么?为什么 Mockito 验证对我传递给函数的参数的调用而不是对函数本身的调用?

最佳答案

正如我在评论中提到的,Mockito 实际上是以非直观的方式有状态的;很多时候, stub 或验证的方法只是“最后调用的方法”,主要是因为像 verify(foo).doA() 这样的语法实际上调用了 doA 而不是传递反射将方法 doA 引用到 Mockito 中。这与在 stub 或验证过程中调用相同模拟的语法不兼容。

我已经 written about this before with regard to Matchers ,在 stub 期间有同样的问题。翻阅源代码,您可以看到与验证相同的问题,至少在对同一个 mock 调用方法时是这样。

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

  1. 调用verify(mockedThing)
  2. 如有必要,按顺序调用匹配器。不要在 mockedThing 上调用任何方法。
  3. 调用您在 mockedThing 上验证的方法,如果您不使用匹配器则使用实际参数值,如果您使用匹配器则使用虚拟(忽略)参数值。由于 Mockito 在后台跟踪匹配器堆栈,匹配器方法可以返回 0null,而 Mockito 不会认为这些是要检查的值。

幕后花絮

调用 verify实际上只是set a flag and return the exact same mock :

public <T> T verify(T mock, VerificationMode mode) {
// [catch errors]
mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, mode));
return mock;
}

然后,inside the handler that handles all mock invocations , Mockito 在验证开始后第一次调用 mock 时开始验证:

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]
}

因此,如果您只是为了获取参数值而与 mock 交互,Mockito 将假设您实际上是在调用该方法来验证。请注意,如果调用略有不同,例如 verify(mockedThing).doB(eq(5), eq(mockedThing.doA())); 和额外的 eq(5),你会收到一条关于滥用匹配器的不同错误消息——特别是因为 Mockito 不只是认为你在验证 doA,而是你以某种方式认为 doA接受争论。

后果

您的代码无效:

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

关于java - 无法在验证 : too many invocations 的参数中使用模拟函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36943640/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com