1

在我的办公室,除了对主要负责与文件系统(数据库等)交互的类进行集成测试外,我们还对单元测试的必要性存在争议。

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


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

  1. 编写单元测试让代码变得更好
  2. 进行单元测试,您无需关心真实的文件系统和文件的副作用,出现在错误的位置
  3. 开发人员可以通过使测试的类使用文件系统模拟并为该模拟设置适当的期望来全面测试结果
  4. 可以将 mock 期望与被测类的特定内部算法联系起来,因为我们使用单元测试进行白盒测试

因此,必须始终为这样的测试类编写单元测试。并且该类必须始终使用文件系统层组件进行测试。


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

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

因此,在我们的案例中不需要使用文件系统模拟进行单元测试。对于这种特殊的类情况,它很脆弱并且不准确。


所以,总而言之,问题是:
对于没有复杂类的边缘情况,集成测试是否足够充分,它主要负责使用文件系统(数据库等)?

此类的集成测试和单元测试之间的唯一区别在于,单元测试将使用文件系统模拟(类将完全隔离),而集成测试使用真实文件系统。

如果您可以添加对经典书籍的引用,或者可能是知名业内人士的文章/演示文稿,我将不胜感激,这样我们就可以有一个非常强大的基础来支持所得出的结论。

4

2 回答 2

1

简短的回答是肯定的,您可以使用“集成”测试来全面测试一个类。不过,更好的问题是你应该这样做吗?

我认为您对“单元测试”(无外部依赖项)和“集成测试”(具有此类依赖项)之间的定义差异过于关注。测试的目标是让您确信您的代码始终在工作,同时降低拥有这种信心的相关成本。所以你的问题

对于没有复杂类的边缘情况,集成测试是否足够充分,该类主要负责使用文件系统(数据库等)?

有点不完整。

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

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

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

编辑

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

要记住的重要一点是您要实现的目标:以可接受的成本建立信心。如果“集成”测试足够便宜,那就太好了。如果您可以使用“单元”测试更便宜地获得相同的信心,那就更好了。确切的组合取决于手头的问题。

于 2013-03-26T14:56:18.900 回答
0

最好有一个已知的文件系统或数据库状态用于测试。例如,您不希望测试失败,因为它试图插入已经存在的记录。此故障不是由于代码而是数据库问题。同样的事情也可能发生在文件系统中。但是,您应该编写您能够编写的最佳测试。如果您不能轻松地模拟文件系统或其他任何东西,请与它进行交互。只要意识到如果测试失败,它可能不是代码问题。

丑陋的测试总比没有测试好。--Testivus之道 http://www.artima.com/weblogs/viewpost.jsp?thread=203994

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

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

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

对于使用模拟进行测试,您不应该与算法绑定。您要测试的只是该类的预期行为。不是它是怎么做的。

于 2013-03-26T14:00:30.263 回答