除了DB,文件系统等的集成测试之外还需要进行单元测试吗?

时间:2013-03-26 05:35:49

标签: unit-testing mocking integration-testing

在我的办公室,除了主要负责与文件系统(DB等)交互的类的集成测试之外,我们还有关于单元测试必要性的争议。

我们拥有的集成测试几乎都是单元测试,因为测试对象根本不与其他对象交互。我们称之为测试集成的唯一原因是真正的文件系统用于测试。并且建议使测试类使用文件系统层组件,然后在测试中模拟它(因此我们将它们称为单元测试),并检查与该组件的交互,而不是真实的文件系统结果。我们讨论的是这种变化的必要性。


我们的一个观点是,总是需要单元测试,因为:

  1. 编写单元测试使代码更好
  2. 进行单元测试,您不需要关心文件的真实文件系统和副作用,出现在错误的位置
  3. 开发人员可以通过使测试类使用文件系统模拟并为该模拟设置正确的期望来完全测试结果
  4. 可以将模拟期望与测试类的特定内部算法联系起来,因为我们使用单元测试进行白盒测试
  5. 因此,必须始终为这样的测试类编写单元测试。并且该类必须始终使用文件系统层组件进行测试。


    另一种观点是,对于专门用于文件系统交互的类的特定边缘情况,不需要单元测试,因为:

    1. 无法通过简单的模拟而不是真正的文件系统(或其完全模拟)来正确验证测试类的工作原理。文件系统是一个如此复杂的组件,它:
      • 测试类可以以多种不同方式工作,以获得成功的结果。模拟期望仅涵盖一两种可能的情况,因此单元测试错误地显示正确实现良好算法的类的失败,这与预期的不同。
      • 测试类可以以某种方式工作,由mock作为成功场景检测,而类仍然不能产生正确的结果。这可能是因为真实文件系统中的原因非常复杂。所有这些原因都不可能仅仅通过模拟来涵盖。
    2. 模拟和期望的单元测试非常脆弱,因为它与测试类的内部算法密切相关。并且即使对算法进行了正确的更改,测试也会错误地失败。
    3. 当类只有1-2个公共方法,并且只有依赖项是文件系统时,集成测试才是一个适当且完全替代案例的单元测试。集成测试为这种情况提供了与单元测试相同的好处 - 明确的依赖性,更易读的代码等。
    4. 因此在我们的案例中不需要使用文件系统模拟进行单元测试。它很脆弱,对于这种特殊的课程来说并不准确。


      所以,总结一下,问题是:
      集成测试是否完全足以应对没有复杂类的边缘情况,主要负责使用文件系统(DB等)?

      此类的集成单元测试之间的唯一区别是,对于单元测试,将使用文件系统mock(类将完全隔离),而与集成测试使用真正的文件系统。

      我很感激,如果您可以添加经典书籍的参考资料,或者可能是知名行业人士的文章/演示文稿,那么我们就可以有一个非常强大的基础来支持最终的结论。

2 个答案:

答案 0 :(得分:1)

这里简短的回答是肯定的,你可以使用'集成'测试完全测试一个类。但是,更好的问题是应该吗?

我认为你对'单元测试'(没有外部依赖)和'集成测试'(具有这样的依赖性)之间的定义差异太过分了。测试的目标是让您确信您的代码始终在工作,同时保持相关的成本降低信心。所以你的问题

  

集成测试是否完全足以满足没有的边缘情况   复杂类,主要负责处理文件系统   (DB等)?

有点不完整。

我们讨论中“单元”和“集成”之间区别的最有用部分是:单元测试编写,维护和运行更容易,更便宜。

要编写单元测试,您只需要知道代码即可。如果单元测试失败,您知道这是因为代码的更改。编写集成测试需要设置依赖项,例如创建具有特定内容的文件,将行插入数据库等。如果集成测试失败,它可能是您的代码,或者它可能是您的依赖项。由于这些原因和其他原因,集成测试更复杂,因此创建,维护和运行更加昂贵。

增加的开销应该促使开发人员将封装业务逻辑的类与处理与外部系统交互的类分开,以尽量减少所需的集成测试的数量。可以使用更便宜的单元测试来测试业务逻辑。

修改

您的类可能有复杂的逻辑本身很复杂,因为它必须处理底层外部依赖项(即相关文件系统)中的复杂行为。在这种情况下,模拟文件系统本身可能非常困难,并且可能更便宜/更容易使用正确设置的文件系统并编写“集成”测试。

要记住的重点是你要努力实现的目标:以可接受的成本获得信心。如果“整合”测试足够便宜,那就太好了。如果使用“单位”测试可以获得相同的信心,甚至更好。具体的混合取决于手头的问题。

答案 1 :(得分:0)

最好具有用于测试的文件系统或DB的已知状态。例如,您不希望测试失败,因为它试图插入已存在的记录。此故障不是由于代码而是由于DB的问题。文件系统中也可能发生同样的事情。但是,您应该编写最好的测试。如果你不能轻易模拟文件系统或其他什么,那么与它进行交互。只要意识到如果测试失败,它可能不是代码的问题。

  

ugle测试比没有测试好。 - 节日之路   http://www.artima.com/weblogs/viewpost.jsp?thread=203994

现在,即使您确实进行了模拟测试,但这并不意味着您不应该进行QA或某种集成测试,以确保所有内容都能正确连接。我认为单元测试用于验证代码的内部是否正常工作,集成测试告诉我所有部分一起工作。

我不知道您使用的是哪种语言,但PHPUnit的文档提供了有关测试数据库和文件系统的一些想法。

  

模拟和期望的单元测试非常脆弱,因为它是   与测试类的内部算法密切相关。而且测试   即使是算法的正确更改也会错误地失败。

对于使用模拟进行测试,您不应该与算法相关。您正在测试的所有内容都是该类的预期行为。不是这样做的。