【问题标题】:Can I set up a Mockito mock with expectations (verify) at instantiation time?我可以在实例化时设置一个带有期望(验证)的 Mockito 模拟吗?
【发布时间】:2016-03-24 00:04:38
【问题描述】:

验证预期方法是否已在 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

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

【问题讨论】:

  • 不确定,但也许定义自定义规则可以解决问题。
  • 我想知道:通常人们更喜欢 Mokito 而不是 EasyMock,因为他们可以像您在第一行中那样写下他们的代码。如果您更喜欢 EasyMock 的做事方式;你不只是使用 EasyMock 吗?
  • @Jägermeister EasyMock 是可行的,但在基于团队的环境中,人们喜欢选择一个通用框架来实现一致性。只是希望有一种方法可以使用 Mockito 实现它。

标签: java unit-testing mocking mockito


【解决方案1】:

更新:这个答案发生了很大变化,因为 Mockito 2 中提供了严格的模拟,而 Mockito 3 中默认提供了对严格存根的强制执行。使用 strictlenient 模式配置这些模拟和存根并查看 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 中模拟严格的模拟,您需要设置一个未通过测试的默认答案,并仅使用 doVerb 方法(doAnswerdoReturndoThrow 等)。此语法向 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());

Mockito 将始终返回最后定义的匹配链上的行为,并且仅在没有匹配的链时使用默认答案,因此您应该能够使用 doVerb 方法定义任意数量的链来覆盖该行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 2014-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多