java - 我可以在实例化时设置一个带有期望(验证)的 Mockito 模拟吗?

标签 java unit-testing mocking mockito

验证预期的方法是否已在 Mockito 中运行通常是这样的:

when(mockFoo.someMethod()).thenReturn(someValue);
// run test
verify(mockFoo, times(n)).someMethod();

有什么方法可以让我在创建模拟时指定验证。在 EasyMock 之类的东西中,我可以这样做:

mockFoo = EasyMock.createMock(Foo.class);
EasyMock.expect(mockFoo.someMethod()).times(n).andReturn(someValue);
// then run test

我的用例是我有一个经常重用的测试依赖项,我想模拟它(doesFooMethodAndReturnBar5Times 模拟),但是使用 Mockito 我没有办法对其执行验证。

最佳答案

更新:这个答案发生了重大变化,因为 Mockito 2 中提供了严格的模拟,而 Mockito 3 中默认情况下将提供对严格 stub 的强制执行。使用 strictlenient 模式来配置这些模拟和 stub 并查看 mockito issue 769用于文档和进度。

在 Mockito 2 之前,这不是 Mockito 可以轻易做到的事情。 EasyMock 的默认严格模拟确保 (1) 意外交互立即失败,以及 (2) 所有预期交互发生;除了 verifyNoMoreInteractions(它不会立即失败,而是在测试结束时失败)之外,Mockito 没有任何设置。这是 philosophical design decision on Mockito's part ,并查看 this thread 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 模拟被命名为“nice mocks”; Mockito 的一大卖点是模拟默认情况下很好,因此它们通常可以容忍与被测试行为无关的调用。这确实使调试变得有点困难,因为 Mockito 不会像 EasyMock 那样在意外交互时立即失败,但它也使测试不那么脆弱——更有可能的是安全更改仍然会破坏测试,因为 EasyMock 模拟接到了一个意想不到的电话。 在进一步进行之前,请与您的团队核实他们是否会对您在此处的选择感到满意:对于 Mockito 而言,严格的模拟语义相对较新并且其中的错误假设可能同样大作为框架变化的交易。 (就这一点而言,在看到替代方案之后,他们最终可能会让您使用 EasyMock!)


要在 Mockito 2+ 中使用严格模拟,请参阅 syntax and libraries in Mockito issue 769 .这可能是从 Mockito 1.x 升级的一个很好的理由。

要在 Mockito 1.x 中模拟严格模拟,您需要设置一个未通过测试的默认 Answer,并仅使用 doVerb 建立正确的行为方法(doAnswerdoReturndoThrow 等)。此语法为 Mockito 提供了停用 stub 行为所需的警告。要创建默认答案,您可以为单个方法(首选)或为单个模拟上的所有方法设置行为。

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 方法定义任意数量的链来覆盖该行为。

关于java - 我可以在实例化时设置一个带有期望(验证)的 Mockito 模拟吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36191021/

相关文章:

java - 无法在 CentOS 7 上启动 kafka 代理

java - 这是一个已知的 IE 错误吗?未将提交参数传递给请求

java - 通过shell脚本将参数从txt文件传递给java文件

c# - Specflow 未在 Visual Studio 2019 中执行测试

python - 在本地测试 Hive + spark python 程序?

python - 如何获取一个 Mock 对象的多个实例

python - 如何模拟类方法的 cls 参数?

java - 为什么实例方法引用适用于不匹配的签名?

.net - .NET多线程和单元测试

组件级别的 Angular 模拟服务