验证预期的方法是否已在Mockito中运行通常如下所示:
when(mockFoo.someMethod()).thenReturn(someValue);
// run test
verify(mockFoo, times(n)).someMethod();
在创建mock时,有什么方法可以指定验证吗。在像EasyMock这样的东西中,我可以做:
mockFoo = EasyMock.createMock(Foo.class);
EasyMock.expect(mockFoo.someMethod()).times(n).andReturn(someValue);
// then run test
我的用例是,我有一个经常重复使用的测试依赖项,我想模拟它(doesFooMethodAndReturnBar5Times模拟),但使用Mockito,我没有办法对其进行验证。
更新:这个答案发生了重大变化,因为Mockito 2中提供了严格的mock,而Mockito 3中默认情况下将提供对严格存根的强制执行。使用strict
和lenient
模式来配置这些mock和stub,并查看mockito问题769中的文档和进度。
在Mockito 2之前,这不是Mockito可以轻易做到的。EasyMock默认的严格模拟确保(1)意外的交互立即失败,(2)所有预期的交互都发生;除了verifyNoMoreInteractions
(它不会立即失败,而是在测试结束时失败)之外,Mockito并没有任何设置。这是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.
EasyMock能够容忍意外调用的mock被命名为"nice mocks";Mockito的一大卖点是,默认情况下mock很好,因此它们通常可以容忍与测试行为无关的调用。这确实让调试变得有点困难,因为Mockito不会像EasyMock那样在意外的交互中立即失败,但它也降低了测试的脆弱性——更可能的是,安全的更改仍然会破坏测试,因为EasyMock-mock收到了意外的调用在继续之前,请与您的团队核实他们是否对您的选择感到满意:对于Mockito来说,严格的mock语义是相对较新的,而破碎的假设可能与框架更改一样重要。(到那时,在看到替代方案后,他们可能会让你使用EasyMock!)
要在Mockito 2+中使用严格的mocks,请参阅Mockito 769期中的语法和库。这可能是从Mockito 1.x升级的一个很好的理由
要在Mockito 1.x中模拟严格的mock,您需要设置一个未通过测试的默认Answer,并且只使用doVerb
方法(doAnswer
、doReturn
、doThrow
等)来建立正确的行为。此语法为Mockito提供了停用存根行为所需的警告。要创建默认的Answer,可以为单个方法(首选)设置行为,也可以为单个mock上的所有方法设置行为。
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());
Mockito将始终返回最后定义的匹配链上的行为,并且只有在没有链匹配的情况下才会使用默认答案,因此您应该能够使用doVerb
方法定义任意数量的链来覆盖该行为。