当多次在mock上调用相同的方法时,Mockito似乎错误地解释了
verifyNoMoreInteractions()
。在下面的示例中,someInterface.doSomething(param)
被多次调用(对于传递的每个参数):
public interface SomeInterface {
int doSomething(int a);
}
public class SomeService {
private final SomeInterface someInterface;
public SomeService(SomeInterface someInterface) {
this.someInterface = someInterface;
}
public int callInterface(int... params) {
int sum = 0;
for (int param : params) {
sum += someInterface.doSomething(param); // call for each param
}
return sum;
}
}
测试:
@ExtendWith(MockitoExtension.class)
class SomeServiceTest {
@Test
public void myTest() {
SomeInterface myInterfaceMock = mock(SomeInterface.class);
SomeService myService = new SomeService(myInterfaceMock);
doReturn(1).when(myInterfaceMock).doSomething(1);
doReturn(2).when(myInterfaceMock).doSomething(2);
doReturn(3).when(myInterfaceMock).doSomething(3);
int sum = myService.callInterface(1, 2, 3);
assertEquals(1 + 2 + 3, sum);
verify(myInterfaceMock).doSomething(1);
verify(myInterfaceMock).doSomething(2);
verifyNoMoreInteractions(myInterfaceMock); // succeeds???
}
}
在上面的示例中,尽管
verifyNoMoreInteractions(myInterfaceMock)
尚未得到验证,但 verify(myInterfaceMock).doSomething(3)
通过了。这意味着仍然与模拟进行交互(即调用myInterface.doSomething(3)
)。这是怎么回事?
注意:如果有另一个调用 SomeInterface.someOtherMethod 而不是 verifyNoMoreInteractions 会发出信号,但上面似乎没有检测到 情况。
我的测试用例的依赖关系:
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
分析文档并考虑来自(@JBNizet)的有用评论后,从 Mockito 版本 3.0 和 JUnit5 开始似乎是预期的行为(使用 Mockito 扩展
@ExtendWith(MockitoExtension.class)
)。
答案可以在Mockito Strictness API的javadoc中找到,我们可以阅读:
STRICT_STUBS
@孵化公共静态最终严格性STRICT_STUBS
确保干净的测试,减少测试代码重复,改进 可调试性。提供灵活性和性能的最佳组合 生产率。强烈推荐。计划作为 Mockito v3 的默认设置。
如果您使用 Mockito.verifyNoMoreInteractions(Object...) 您不再需要 显式验证存根调用。它们会自动验证 为你。
因此存根方法调用会自动验证!
这是什么意思?如果我们举个例子,给出的问题中,编写测试完全省略对
verify(myInterfaceMock).doSomething(x)
的调用就足够了。只需将电话留给verifyNoMoreInteractions(myInterfaceMock)
就足够了。因此这个测试也成功了:
@Test
public void myTest() {
SomeInterface myInterfaceMock = mock(SomeInterface.class);
SomeService myService = new SomeService(myInterfaceMock);
doReturn(1).when(myInterfaceMock).doSomething(1);
doReturn(2).when(myInterfaceMock).doSomething(2);
doReturn(3).when(myInterfaceMock).doSomething(3);
int sum = myService.callInterface(1, 2, 3);
assertEquals(1 + 2 + 3, sum);
verifyNoMoreInteractions(myInterfaceMock); // NOTE: no individual verify(myInterfaceMock) calls (!)
}
Mockito 怎么知道叫什么?因为它分析存根。 Mockito 根据这段代码找出应该验证哪些方法:
doReturn(1).when(myInterfaceMock).doSomething(1);
doReturn(2).when(myInterfaceMock).doSomething(2);
doReturn(3).when(myInterfaceMock).doSomething(3);
Mockito,似乎在说“嘿伙计,你期待
myInterfaceMock
打电话给doSomething(1)
,所以如果你打电话给verifyNoMoreInteractions()
,我会验证doSomething(1)
是否真的被叫了......所以个人期望verify(myInterfaceMock).doSomething(1)
是多余的。
如果需要,可以通过将
verify()
更改为 Strictness
来启用对 WARN
的各个调用的自动验证,这可以通过 @MockitoSettings(strictness = Strictness.WARN)
来实现
以下版本的测试按最初预期失败:
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.WARN)
class SomeServiceTest {
@Test
public void myTest() {
SomeInterface myInterfaceMock = mock(SomeInterface.class);
SomeService myService = new SomeService(myInterfaceMock);
doReturn(1).when(myInterfaceMock).doSomething(1);
doReturn(2).when(myInterfaceMock).doSomething(2);
doReturn(3).when(myInterfaceMock).doSomething(3);
int sum = myService.callInterface(1, 2, 3);
assertEquals(1 + 2 + 3, sum);
verify(myInterfaceMock).doSomething(1);
verify(myInterfaceMock).doSomething(2);
verifyNoMoreInteractions(myInterfaceMock);
}
}
留言:
org.mockito.exceptions.verification.NoInteractionsWanted:
No interactions wanted here:
-> at SomeServiceTest.myTest(SomeServiceTest.java:30)
But found this interaction on mock 'someInterface':
-> at SomeService.callInterface(SomeService.java:13)
***
For your reference, here is the list of all invocations ([?] - means unverified).
1. -> at SomeService.callInterface(SomeService.java:13)
2. -> at SomeService.callInterface(SomeService.java:13)
3. [?]-> at SomeService.callInterface(SomeService.java:13)
这似乎取决于测试的设计者他/她想使用哪个 Strictess。新的默认严格性 - STRICT_STUBS 肯定会减少编写的测试代码量