当发生意外调用时,如何让 Mockito 模拟导致失败?

4 java unit-testing mocking mockito

我有一些模拟对象可能会稍微传递一下,最终可能会变得相当复杂。

我想让 Mockito 为每次模拟调用输出日志,或者我希望它在发生意外调用时失败,以便我可以遍历这些调用并设置适当的响应。

我怎样才能做到这一点?

Jef*_*ica 5

最惯用的方法是使用verifyNoMoreInteractions,如Mockito 文档 #8 中所示

//interactions
mock.doSomething();
mock.doSomethingUnexpected();

//verification
verify(mock).doSomething();

//following will fail because 'doSomethingUnexpected()' is unexpected
verifyNoMoreInteractions(mock);
Run Code Online (Sandbox Code Playgroud)

我在上面说“最惯用的”是因为该方法有自己的警告标签,该标签链接到博客文章“我应该担心意外吗?” 由 Mockito 创始人 Szczepan Faber 撰写。

verifyNoMoreInteractions()不建议在每个测试方法中使用。verifyNoMoreInteractions()是来自交互测试工具包的一个方便的断言。仅在相关时使用它。滥用它会导致过度指定、不易维护的测试。

简而言之,您应该有一个非常明确的理由来检查您的依赖项没有做什么或您的被测系统没有调用什么,而不是他们正在做什么和调用什么。verifyNoMoreInteractions如果您想避免不必要的 RPC 调用,您可以使用RPC 对象,而不是(例如)没有副作用的计算器。更好的是使用never()times(int)作为参数指定您的确切要求verify


也就是说,有两种更不惯用的方法来做到这一点:

  • 您可以记录使用mockingDetails(Object)和迭代调用的整体日志getInvocations()。这应该会反射性地为您提供完整的调用列表。我很难想象这在测试中会有什么用处,但它可能有助于清理模糊或记录不良的现有系统。

  • 您可以使模拟的默认操作引发异常,这意味着如果有人调用了您尚未存根的内容,则测试将立即失败。

    // untested pseudocode
    YourObject yourObject = Mockito.mock(YourObject.class, withSettings()
        .defaultAnswer(invocation -> {
          throw new UnsupportedOperationException(invocation.toString());
        }));
    
    Run Code Online (Sandbox Code Playgroud)

    当然,这倒是工作,但你不仅(违反的的Mockito的核心原则之一嘲笑是很好的默认情况下使用,“好”的了EasyMock的定义),但你也想用强迫自己只存根doVerbdoReturndoAnswer,等),因为调用 towhen(yourObject.doAnything())必然会在调用 towhen运行之前抛出该异常。

    熟悉 Mockito 的开发人员可能会说,这种容易出现异常的治疗方法比疾病更糟糕,并且可能仅用于临时诊断最混乱的遗留代码。

  • `verifyNoMoreInteractions()` 很少有用,因为当您可以返回到测试方法来调用它时,被测试的组件已经继续尝试对它意外得到的 `null` 执行某些操作称呼。默认的操作解决方案绝对是OP想要的。 (4认同)
  • 我仍然可以通过编写一个 defaultAnswer 来使用“when(...).thenReturn(...)”,如果未设置静态布尔值,则返回 null;如果设置了静态布尔值,则返回异常。我将布尔值设置为 false 来设置模拟,然后将其设置为 true 并运行正在测试的方法,它向我展示了我需要模拟的缺少的方法是什么。非常老套,但我只用它来诊断,然后在进行有效测试后将其全部删除。 (2认同)