ChatGPT解决这个技术问题 Extra ChatGPT

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

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

例如:

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

M
Michael Xin Sun

更有意义:

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

// ...

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

此功能的文档在 §4 "Verifying exact number of invocations / at least x / never"never javadoc 是 here


使用 never 是最好和最具体的方法,但如果您需要检查整个模拟对象,也可以考虑 verifyZeroInteractions(mockObject)verifyNoMoreInteractions(mockObject)
如果 someMethod 是私有的怎么办?
然后你不能首先模拟它(使用 Mockito);) PowerMock 允许这样做,但设置起来更复杂。或者,如果您拥有代码的所有权,则可以放宽对包的可见性。
从 3.0.1 开始,verifyZeroInteractions 已被弃用。 verifyNoInteractions 是建议的替代方案。发表此评论时的 Mockito 版本是 3.3.3
N
Naman

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

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

public static VerificationMode never() { return times(0); }
never() 的可读性并不比 times(0) 高很多。但是 never 的存在确实增加了认知负荷,使 mockito 系统更难理解和记住如何使用。所以真正的 mockito 不应该在他们的 API 中包含 never,它不值得付出精神上的代价。
问题:此表单是否验证 someMethod 被调用 0 次,还是仅验证 someMethod 从未使用零参数调用?
@BT - 我想它会验证具有零参数的 someMethod 被称为零次 - 未验证。
同样适用于 jmockit btw, times=0;
D
David Lavender

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

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

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

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

所以我发现这种模式对于捕获所有未经过特别验证的意外调用很有用。


Mockito 文档指出这种模式不应该被滥用——“一个警告:一些做了很多经典的、expect-run-verify 模拟的用户倾向于经常使用 verifyNoMoreInteractions(),即使在每个测试方法中也是如此。verifyNoMoreInteractions () 不建议在每个测试方法中使用。verifyNoMoreInteractions() 是来自交互测试工具包的一个方便的断言。仅在相关时使用它。滥用它会导致过度指定、难以维护的测试。请参阅here
“仅在相关时使用它”。我觉得它总是相关的。我不认为这种模式是滥用:就像我说的,它发现“事情被称为不应该被称为”。对我来说,这是一个至关重要的验证:如果有东西正在调用它不应该使用的存储库,我想知道它!除非有另一种方法可以在不使用 verifyNoMoreInteractions 的情况下进行验证?这里的其他答案依赖于测试作者明确记得列出这些检查:这在我的书中太容易出错了。
我看到了这个评论,但也觉得推理没有说服力。我很想阅读更多关于为什么不推荐这样做的信息。
@tobinibot 因为单元测试的想法是验证合同。大多数合约通常不涉及调用其他方法的次数,而是传递已知参数会导致已知响应。通过不再使用交互,您基本上是在逐行验证实现,这使得重构和实现变得乏味。这不是单元测试的重点。
我遇到过很多次我们验证没有调用某些东西,然后将实现更改为调用其他东西..旧测试仍然通过,因为旧方法仍然没有被调用,但我们没有验证新方法方法。此处建议的模式将有助于确保您的测试保持相关性 - 如果您更新代码而不更新测试,您可能有隐藏的问题并假设您的测试仍然涵盖它。我同意@DavidLavender:“这里的其他答案依赖于测试作者明确记得列出这些检查:这在我的书中太容易出错了。”
f
fl0w

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

import static org.mockito.Mockito.*;

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

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

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

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

替代方案是:

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

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

verifyZeroInteractions(yourMock)

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

verifyNoInteractions(yourMock)

b
byxor

verifyNoMoreInteractions()verifyZeroInteractions() 方法在内部具有与以下相同的实现:

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

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

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


瞬态用于字段
A
Alex Blasco

正如一个建议,如果您想在语法级别与 Behavior-driven development 样式更加一致,则有 BDDMockito

你可以使用:

then(dependency).should(never()).someMethod();

作为等效替换:

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