如何验证使用Mockito不调用特定方法?

bel*_*hin 563 java tdd mockito

如何验证是否在对象的依赖项上调用方法?

例如:

public interface Dependency {
    void someMethod();
}

public class Foo {
    public bar(final Dependency d) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

通过Foo测试:

public class FooTest {
    @Test
    public void dependencyIsNotCalled() {
        final Foo foo = new Foo(...);
        final Dependency dependency = mock(Dependency.class);
        foo.bar(dependency);
        **// verify here that someMethod was not called??**
    }
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ice 983

更有意义的是:

import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

// ...

verify(dependency, never()).someMethod();
Run Code Online (Sandbox Code Playgroud)

该功能的文档是§4"验证确切的调用次数/至少x/never",neverjavadoc就在这里.

  • 使用`never`是最好和最具体的方法,但如果你需要检查整个模拟对象,还要考虑`verifyZeroInteractions(mockObject)`或`verifyNoMoreInteractions(mockObject)`. (127认同)
  • 自 3.0.1 起,“verifyZeroInteractions”已被弃用。`verifyNoInteractions` 是建议的替代方案。发表此评论时的 Mockito 版本是 3.3.3 (11认同)

bel*_*hin 104

Mockito.verify方法上使用第二个参数,如:

verify(dependency, Mockito.times(0)).someMethod()

  • `Mockito.never()`是一种更具表现力/可读性的选择. (47认同)
  • public static VerificationMode never(){return times(0); } (7认同)
  • “ never()”的可读性并不比“ times(0)”明显。但是“从不”的存在确实增加了认知负担,并使模仿系统变得难以理解和记住如何使用。因此,实际上,Mockito不应在其API中包含“从不”,这不值得花费精神上的代价。 (3认同)

Dav*_*der 18

作为一个更普遍的模式,我倾向于@After在测试中使用一个块:

@After
public void after() {
    verifyNoMoreInteractions(<your mock1>, <your mock2>...);
}
Run Code Online (Sandbox Code Playgroud)

然后测试可以自由地仅验证应该调用的内容.

此外,我发现我经常忘记检查"没有互动",只是为了后来发现事情被称为不应该被调用.

因此,我发现此模式对于捕获未经过特别验证的所有意外调用非常有用.

  • Mockito文档指出不应该滥用这种模式 - "一句警告:一些做过许多经典的,期望运行验证模拟的用户往往会经常使用verifyNoMoreInteractions(),即使在每个测试方法中也是如此.enifyNoMoreInteractions建议不要在每个测试方法中使用().coerctNoMoreInteractions()是交互测试工具包中的一个方便的断言.只有在它相关时才使用它.滥用它会导致过度指定,维护较少的测试." 见[here](http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html#8) (8认同)
  • “仅在相关时使用它”。我觉得它总是相关的。我不认为这种模式是滥用:就像我说的那样,它发现“被称为不应该被称为的东西”。对我来说,这是一个至关重要的验证:如果有什么东西调用了它不应该使用的存储库,我想知道它!除非有另一种方法可以在不使用“verifyNoMoreInteractions”的情况下进行验证?这里的其他答案依赖于测试作者明确记住列出这些检查:在我的书中这太容易出错了。 (3认同)
  • 我看到了这个评论,但也觉得这个推理并不引人注目.我想更多地了解为什么不建议这样做. (2认同)
  • @tobinibot 因为单元测试的想法是验证合约。大多数合同通常不涉及调用其他方法的次数,而是传入已知参数会导致已知响应。通过不再使用交互,您基本上是在逐行验证实现,这使得重构和实现变得乏味。这不是单元测试的重点。 (2认同)

fl0*_*l0w 14

首先:您应该始终导入 mockito static,这样代码将更具可读性(和直观):

import static org.mockito.Mockito.*;
Run Code Online (Sandbox Code Playgroud)

实际上有很多方法可以实现这一点,但是(可以说)使用

verify(yourMock, times(0)).someMethod();
Run Code Online (Sandbox Code Playgroud)

整个测试中的方法,当在其他测试中使用它来断言一定数量的执行时,如下所示:

verify(yourMock, times(5)).someMethod();
Run Code Online (Sandbox Code Playgroud)

替代方案是:

verify(yourMock, never()).someMethod();
Run Code Online (Sandbox Code Playgroud)

或者 - 当你真的想确保某个模拟对象实际上根本没有被调用时 - 你可以使用:

verifyZeroInteractions(yourMock)
Run Code Online (Sandbox Code Playgroud)

请注意:不推荐使用 verifyZeroInteractions(Object... mocks)。从 3.0.1 版开始。现在推荐的方法是:

verifyNoInteractions(yourMock)
Run Code Online (Sandbox Code Playgroud)


Ujj*_*wal 8

这里的verifyNoMoreInteractions()verifyZeroInteracions()方法都具有相同的实现:

public static transient void verifyNoMoreInteractions(Object mocks[])
{
    MOCKITO_CORE.verifyNoMoreInteractions(mocks);
}

public static transient void verifyZeroInteractions(Object mocks[])
{
    MOCKITO_CORE.verifyNoMoreInteractions(mocks);
}
Run Code Online (Sandbox Code Playgroud)

所以我们可以在模拟对象或模拟对象数组中使用它们中的任何一个来检查是否没有使用模拟对象调用任何方法.