【问题标题】:Do I need to verify interaction with mocks or just check the method inputs and outputs?我需要验证与模拟的交互还是只检查方法输入和输出?
【发布时间】:2015-02-16 15:57:57
【问题描述】:

是否有必要验证与 Mock 对象的交互?所以假设我有一堂课:

Class A{
    B b;

    public A(B b){
       this.b = b;
    }

    int getObjectFromDatabase(int id){
       Object o = b.get(id);
       // do some extra work
       return result
    }
}

现在我正在测试getObjectFromDatabase 方法。我已经通过了 B 类的 Mock 对象。我是否需要验证是否正在调用 b.get(id) 的交互?还是只检查我得到的输入和输出结果是个好主意?

【问题讨论】:

    标签: unit-testing mocking mockito


    【解决方案1】:

    一般来说,验证存根调用是否发生是不必要的,并且会导致脆弱的测试(即使实现保持正确,测试也会失败)。在您的情况下,是否调用 get(id) 或调用多少次可能并不重要;重要的是返回的对象是否正确,并且可能需要在某些时候调用 b.get(id) 才能获得正确的结果。

    Mockito 有一些 explicit advice in its verify(T) Javadoc:

    虽然可以验证存根调用,但通常只是多余的。假设你已经存根 foo.bar()。如果您的代码关心 foo.bar() 返回的内容,则其他内容会中断(通常甚至在执行 verify() 之前)。如果您的代码不关心 get(0) 返回的内容,则不应将其存根。不服气?见here

    虽然在测试缓存或延迟加载行为时,或者在交互是测试行为的关键部分的其他情况下,verify(b).get(id) 一定次数(包括零次)可能是有意义的,但努力测试正确的输出/状态,而不是验证您的预期交互

    【讨论】:

    • 说得好。这是关于嘲笑的最难学习的课程之一,我仍然发现自己犯了罪。
    • 不验证存根调用可能会给你一个“谎言”测试,但是,当被测代码没有匹配的调用发生时;在这种情况下,开发人员可能希望修复 CUT(因此确实会发生丢失的调用)或修复测试(通过删除不必要的存根)。理想情况下,模拟 API 应该隐式验证每个存根调用,以防止这些可能性。
    • Rogério:隐式验证是 EasyMock 背后的哲学,Mockito deliberately forked into "all mocks are nice" behavior。如果调用对测试很重要,请明确验证它;如果不是,请不要,最坏的情况是您将需要清理额外的存根。许多人发现要求对每个实现更改(不是接口/合同更改)进行测试修复会破坏 TDD 的意义,但如果您不同意,您可以随时在 @After 方法中的每个模拟上调用 verifyNoMoreInteractions
    • (我确实承认您是 JMockit 的创建者,并且拥有 a nice comparison matrix available;我只是说严格和漂亮的模拟都有它们的位置。)
    猜你喜欢
    • 2015-06-09
    • 2021-01-03
    • 1970-01-01
    • 2016-05-25
    • 2015-05-23
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    相关资源
    最近更新 更多