首页 文章

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

提问于
浏览
3

验证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

我的用例是我有一个常用的测试依赖项,我想模拟(didFooMethodAndReturnBar5Times模拟),但是对于Mockito,我没有办法对其强制执行验证 .

1 回答

  • 4

    UPDATE: 这个答案发生了重大变化,因为Mockito 2中提供了严格的模拟,默认情况下Mockito 3中将提供严格存根的强制执行 . 使用 strictlenient 模式配置这些模拟和存根,并查看mockito issue 769以获取文档和进度 .

    在Mockito 2之前,这不是Mockito可以轻易做到的事情 . EasyMock 's default strict mocks ensure that (1) unexpected interactions fail immediately and (2) all expected interactions happen; Mockito didn' t有一个设置,除了 verifyNoMoreInteractions (它不会立即失败,而是在测试结束时) . 这是一个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!)


    To use strict mocks in Mockito 2+,syntax and libraries in Mockito issue 769 . 这可能是从Mockito 1.x升级的一个很好的理由 .

    To emulate strict mocks in Mockito 1.x ,您需要设置未通过测试的默认答案,并且仅使用 doVerb 方法( doAnswerdoReturndoThrow 等) Build 正确的行为 . 此语法为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 方法定义任意数量的链来覆盖该行为 .

相关问题