我应该模拟测试对象与之交互的所有对象吗?

时间:2016-11-14 18:24:05

标签: java unit-testing mockito

我很难知道如何判断我的测试对象与之交互的对象应该被模拟。

class MyClass {
  private Customer customer;
  private Invoice invoice;
  private PrintService ps;
  private DBAccessService da;
  private EmailService em;
  ..........
 }

我可以看到最后3个被嘲笑,因为它们涉及一些外部系统。客户和发票怎么样?如果没有,为什么?

1 个答案:

答案 0 :(得分:4)

问题的一般答案“我应该模拟我的测试对象与之交互的所有对象吗?”是一个响亮的:这不是你应该内化或遵循的规则。模拟是许多类型的测试双重之一,你必须使用判断在哪里使用模拟,在哪里使用其他假货或测试双打,以及在哪里使用真正的合作者。我同意你的决定,即最后三个字段(服务)可能值得嘲笑,如果由我决定,我会使用前两个字段(客户和发票)的真实对象。

在这里,我会坚持一个指南,不要模拟数据对象,这可以从一些观察结果中得出:

  • 数据对象通常非常有状态,而且模拟框架往往状态不佳。对于“getX无限期返回15,Mockito实际上没有很好的语法,直到你拨打setX(20),然后getX返回20”。因此,正确存根通常很难。

  • 对于只是字段/ getter / setter的数据对象,通过从实际实现中读取可变状态来验证无法完成的工作没有太大价值。只要读取对象中的值,谁会关心是否调用了getY?谁关心setY被调用的次数,只要正确的值最终在对象中?因此,验证通常是不必要的。

  • 数据对象通常在使用它们的对象之前编写,因此通常存在一个已经存在的工作实现。

  • 数据对象通常具有确定的行为,几乎没有外部交互作用,因此在提高测试稳定性或降低测试片状度方面通常没什么好处。

问题评论中提到biziclop

  

始终记住自动化测试的目的是:尽可能以最小的努力在尽可能短的时间内找到错误。或者转过身来:建立对代码正确性的信心。

从这个意义上讲,模拟数据对象的可读性和测试的正确性成本很高,并且也不太可能提供有关测试正确性或稳定性的好处。我会避免它。