Mockito模拟对重构时单位测试的影响

时间:2015-09-30 19:13:54

标签: java refactoring tdd mockito

如果我使用一个被注入SUT的对象的mockito模拟作为参数,如果在重构期间重新组织代码以调用同一个模拟的另一个非模拟方法会发生什么?我的测试会失败,我必须返回并更改我的测试并为这个新调用设置它们(与重构代码时我想要做的相反)

如果这在重构期间很常见,那么除了在模拟外部资源密集型实体(网络,数据库等)时,如何使用模拟作为任何用途?

我使用模拟来模拟需要数小时设置的对象,因为我的团队似乎喜欢怪异的深层聚合对象。

谢谢!

2 个答案:

答案 0 :(得分:1)

你是正确的,重构可能会破坏依赖于模拟的代码。 Mockito不知道方法foo(int start, int end)foo(int start)完成同样的事情,如果你在重构时在它们之间切换,你的Mockito模拟很可能会破坏。 Mockito确实为未被调用的调用提供了合理的默认值,例如0,null或空列表;然而,许多重构需要更现实的价值观。

一般来说,我听说当系统行为正常时,测试或测试夹具失效的倾向称为“脆性”。

部分原因是通过选择模拟框架得出的结果:Mockito以EasyMock的分支开始生活,如果有太多或太少的电话,EasyMock默认会失败,但Mockito会忽略意外的来电,否则提供“很好”的默认行为。另一部分取决于您如何使用框架,其中验证不必要的细节(不重要的调用或参数)可能会使模拟比它们更加脆弱。

Mockito善于嘲笑:

  • 外部资源密集型依赖项(或其包装器)。
  • 接口。这里很少会出错。
  • 小API表面。如果您的API表面有一个或两个方法,则不太可能捕捉到您所描述的情况。
  • 尚不存在的协作者,即使他们拥有大型API表面。临时脆性测试可以在以后修复。

Mockito的事情不适合嘲笑:

  • 非常大的API表面和DSL。想象一下用Mockito实现Builder模式!更喜欢使用真实对象,或者编写内存中的伪造或其他测试双。
  • 有状态的对象,如数据库和模型对象。如果真实物体不行,假货绝对是一个更好的选择。
  • 您无法控制的具体课程。此时,final选项的实现细节开始潜入。这可能是创建您控制的包装器的一个很好的理由。
  • 任何具有现有且经过良好测试的实施方案。为什么要在真正的实施中遇到麻烦并失去测试保真度?

值得一提的是没有测试双重将是完全安全的;您的系统可以缓存,组合,延迟,修改或以其他方式调整与其协作者的交互,所有这些都可以打破您编写的任何测试双倍。编写灵活测试的艺术是尽可能少地依赖实现细节,平衡脆弱的风险与彻底测试系统及其与外部世界的交互的要求。

所有这些都说,要直接回答“如何使用模拟有用”的问题,请参阅JB Nizet的great analogy here:如果你想创建一个炸弹雷管,你可能想测试一下,但使用真品的成本太高了。所涉及的困难(以及测试双倍的最佳选择)将根据所讨论的炸弹是否有一百个小触发器或单个boom()方法而有所不同。

有关测试双打(包括模拟,假货和虚拟对象的类别)及其优缺点的更多详细信息,请参阅Martin Fowler的文章"Mocks aren't Stubs"

答案 1 :(得分:0)

我建议你只是嘲笑所需要的最低限度。 Mockito有很多设施可以做到这一点(间谍,当某种方法以某种方式调用时返回特定数据/模拟的能力等),但它最终归结为可测试的接缝"在你的代码中。如果您还没有,我建议您阅读Michael Feather的书Working Effectively with Legacy Code,以获取有关如何执行此操作的许多建议。