Nat*_*han 3 java unit-testing mocking mockito
验证预期的方法是否已在 Mockito 中运行通常是这样的:
when(mockFoo.someMethod()).thenReturn(someValue);
// run test
verify(mockFoo, times(n)).someMethod();
Run Code Online (Sandbox Code Playgroud)
我有什么方法可以在创建模拟时指定验证。在像 EasyMock 这样的东西中,我可以做到:
mockFoo = EasyMock.createMock(Foo.class);
EasyMock.expect(mockFoo.someMethod()).times(n).andReturn(someValue);
// then run test
Run Code Online (Sandbox Code Playgroud)
我的用例是我有一个经常重用的测试依赖项,我想模拟它(doesFooMethodAndReturnBar5Times 模拟),但是对于 Mockito,我没有办法对其进行验证。
更新:这个答案已经发生了重大变化,因为 Mockito 2 中提供了严格的模拟,strict并且在 Mockito 3 中默认可以使用严格的存根。使用和lenient模式来配置这些模拟和存根,并查看mockito 问题 769以获取文档和进度.
在 Mockito 2 之前,这不是 Mockito 可以轻松做到的。EasyMock 的默认严格模拟确保 (1) 意外的交互立即失败和 (2) 所有预期的交互发生;Mockito 没有任何设置,除了verifyNoMoreInteractions(不会立即失败,而是在测试结束时)。这是Mockito 部分的哲学设计决策,请参阅Mockito 发起者进一步讨论的线程。
事实上,Mockito 的when语法依赖于它允许意外交互,因为意外交互告诉 Mockito 调用了哪个方法:
when(mockFoo.someMethod()).thenReturn(someValue);
// ^^^^^^^^^^^^^^^^^^^^ Java calls this first to get an argument for when,
// which is how Mockito knows which method to stub:
// it's always the last one called.
Run Code Online (Sandbox Code Playgroud)
可以容忍意外调用的 EasyMock 模拟被命名为“nice Mock”;Mockito 的一大卖点是默认情况下模拟很好,因此它们通常可以容忍与被测试行为无关的调用。这确实使调试变得有点困难,因为 Mockito 不会像 EasyMock 那样在意外交互中立即失败,但它也使测试不那么脆弱——因为 EasyMock 模拟,安全更改更有可能仍然破坏测试接到一个意外电话。在进一步进行之前,请与您的团队确认他们是否会对您在此处的选择感到满意:严格的模拟语义适用相对较新于 Mockito,而破坏的假设可能与框架更改一样重要。(到那时,在看到替代方案后,他们毕竟可能会让您使用 EasyMock!
要在 Mockito 2+ 中使用严格模拟,请参阅Mockito 问题 769 中的语法和库。这可能是从 Mockito 1.x 升级的一个很好的理由。
为了模拟在1.x的的Mockito严格嘲笑,你就需要设置测试失败默认的答案,也只用建立您的正确的行为doVerb方式(doAnswer,doReturn,doThrow等)。此语法为 Mockito 提供了停用存根行为所需的警告。要创建默认答案,您可以为单个方法(首选)或单个模拟上的所有方法设置行为。
public class ThrowingAnswer extends Answer<Object> {
@Override public Object answer(InvocationOnMock invocation) {
throw new AssertionError("Unexpected invocation: " + invocation);
}
}
// apply to the entire object:
YourObject yourObject = Mockito.mock(YourObject.class, new ThrowingAnswer());
// or per-method:
YourObject yourObject = Mockito.mock(YourObject.class);
doAnswer(new ThrowingAnswer()).when(yourObject).scaryMethod(any());
Run Code Online (Sandbox Code Playgroud)
Mockito 将始终返回最后定义的匹配链上的行为,并且仅在没有链匹配时才使用默认答案,因此您应该能够定义任意数量的链,并doVerb使用覆盖该行为的方法。