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


625

如何验证对对象的依赖项调用方法?

例如:

public interface Dependency {
    void someMethod();
}

public class Foo {
    public bar(final Dependency d) {
        ...
    }
}

通过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??**
    }
}

Answers:


1087

更有意义的是:

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

// ...

verify(dependency, never()).someMethod();

有关此功能的文档,请参见§4“验证确切的调用次数/至少x /从不”,并且neverJavadoc在此处


144
使用never是最好和最具体的方法,但是如果您需要检查整个模拟对象,请考虑verifyZeroInteractions(mockObject)verifyNoMoreInteractions(mockObject)
杰夫·鲍曼

如果someMethod是私有的怎么办?
Sumit Kumar Saha,

1
然后,您不能首先模拟它(使用Mockito);)PowerMock允许这样做,但是设置起来比较复杂。或者,如果您拥有代码的所有权,则可以放宽对包的可见性。
布里斯

2
从3.0.1 verifyZeroInteractions开始不推荐使用。 verifyNoInteractions 是建议的替代方法。发表评论时的Mockito版本是3.3.3
VKB

108

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

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


11
公共静态VerificationMode never(){return times(0); }
gbero

3
never()可读性不比times(0)。但是,存在never的确会增加认知负担,并使模仿系统变得难以理解和记住如何使用。因此,实际上,Mockito不应never在其API中包含它,这不值得花费精神上的代价。
英国电信

问题:此表单是否验证了someMethod被调用0次,还是仅验证了someMethod从未使用零参数进行调用?
英国电信

@BT-我想它会验证someMethod带有零参数的称为零次-未验证。
beluchin

18

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

@After
public void after() {
    verifyNoMoreInteractions(<your mock1>, <your mock2>...);
}

这样,测试就可以自由地仅验证调用的内容。

另外,我发现我经常忘记检查“无交互作用”,只是后来才发现应该调用的东西本来不应该的。

因此,我发现这种模式对于捕获所有未经特别验证的意外呼叫很有用。


9
Mockito文档指出,不应滥用此模式-“警告:有些用户做了很多经典的,期望运行验证的模拟,即使在每种测试方法中,也经常会使用verifyNoMoreInteractions()。 ()不建议在每种测试方法中都使用()。verifyNoMoreInteractions()是来自交互测试工具包的便捷断言。仅在相关时使用它。滥用它会导致规格过多,难以维护的测试。” 看到这里
Chadi

2
“仅在相关时使用”。我觉得这一直很重要。我不认为这种模式是滥用:就像我说的那样,它发现“被称为不应该的东西”。对我来说,这是至关重要的验证步骤:如果某个东西在调用它不应该使用的存储库,那么我想知道这一点!除非有另一种方法可以验证而不使用verifyNoMoreInteractions?这里的其他答案取决于测试作者明确记住要列出这些检查:在我的书中太容易出错了。
David Lavender

2
我看到了此评论,但也觉得推理没有说服力。我很想阅读更多有关为什么不建议这样做的信息。
tobinibot

2
@tobinibot因为单元测试的想法是验证合同。大多数合同通常不涉及调用其他方法的次数,而是传递已知参数会导致已知响应。通过不再使用交互,您基本上可以逐行验证实现,这使得重构和实现变得乏味。这不是单元测试的重点。
Andrew T Finnell

8

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

import static org.mockito.Mockito.*;

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

verify(yourMock, times(0)).someMethod();

方法遍及您的所有测试,当您在其他测试上使用该方法来断言一定数量的执行,如下所示:

verify(yourMock, times(5)).someMethod();

替代方法是:

verify(yourMock, never()).someMethod();

另外,当您确实要确定某个模拟对象实际上根本没有被调用时,可以使用:

verifyZeroInteractions(yourMock)

7

无论是verifyNoMoreInteractions()verifyZeroInteractions()方法在内部具有相同的执行情况:

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

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

因此我们可以在模拟对象或模拟对象数组上使用它们中的任何一个,以检查是否没有使用模拟对象调用任何方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.