单元测试成为 TDD 的集成测试

Unit Tests become Integration Tests with TDD

假设我正在编写一个使用测试驱动开发的应用程序。 我找到的所有样本都是非常小的例子,它们试图解释如何用 TDD 编写测试。

当您在 TDD 中编写测试时,您编写了一小段代码,其目的是测试一段代码、一个方法,因此是一个单元测试。

一段时间后,收到客户的要求,您需要更改原始代码,使其能够接受更多参数,并将方法拆分为多个层上的多个方法。

假设发生故障时添加日志记录。那我需要测试什么,日志组件单独测试,还是与原始方法链接在一起?

这意味着原来的单元测试实际上变成了集成测试,因为我现在正在一起测试多个组件。

这是应该避免的事情吗?或者如果需要,如何解决这类问题?

亲切的问候

现实世界中的TDD实际上同时使用了单元测试和集成测试。在教程中看到单元测试是因为它更容易理解简单的例子,但真正的应用程序需要一些集成测试。您编写的第一个测试通常是集成测试(参见 )。

但是,集成测试速度慢且难以维护(与单元测试相比,它们接触的系统更多,因此更改更频繁),因此最好根据需要进行尽可能多的集成测试并尽可能多地执行你的单元测试测试是合理的。

当 class 的要求导致它变大并且您将 class 重构为更小的 class 时,它的单元测试现在是集成测试。通过为新的 classes 编写有针对性的单元测试并删除原始 class 的大部分旧测试来解决这个问题。留下一个或几个旧测试作为集成测试可能是合适的。重写一些旧测试以使用测试替身(存根、模拟等)作为其他 classes 现在的实例也可能是合适的。巧合的是,我最近写了.

无论是否为 TDD,单元测试的思想是隔离应用程序的一个单元并单独验证其代码流。一个单元通常是 class 并且您会在方法的每个代码分支中查看至少一个单元测试。例如。如果 classA.methodA() 有 3 个分支,您将对该方法进行 3+ 个单元测试。

真正的单元测试将 mocked/stubbed 依赖项注入组件,调用要测试的方法并验证其行为 and/or 对象状态。原则上,单元测试应该鼓励您在松散耦合、关注点分离等方面改进源代码的设计(SOLID 原则)。

此外,代码覆盖率是衡量单元测试质量的一个很好的指标,但不建议力求达到 100%。此外,为每个应用程序层编写单元测试是多余的;您可能希望以包含业务逻辑的层为目标,以实现良好的 return 投资。最后,不要在没有持续集成管道的情况下编写单元测试,因为它们往往很快就会过时。

相反,当您开始将两个或多个单元作为一个测试进行验证时,它就变成了集成测试,因为您的测试结果会受到每个单元的成功或失败的影响。这些往往需要更多的努力来设置环境,可能由于外部依赖性而不稳定,并且可能根据交易量而变慢。这些绝对有用,您应该根据您的预算限制瞄准代码覆盖率。集成测试也应该是 CI/CD 管道的一部分,但可能 运行 比单元测试少。

希望这对您有所帮助。

单元测试和集成测试之间没有真正的根本区别。

您的 类 之一的低级(单元)测试也可能会执行并依赖于您的运行时环境或应用程序框架提供的 类。所以你的单元测试也可以看作是你的代码和运行环境的代码结合的集成测试。

由于它们之间没有根本区别,因此没有理由担心曾经标记为 "unit test" 的内容现在标记为 "integration test"。

除了其他答案,您还可以看看extended TDD cycle as defined in the book Growing Object-Oriented Software Guided by Tests。他们正在使用验收测试来驱动编写单元测试的内部循环;但是,根据情况,我发现您也可以使用集成测试来做到这一点。

所以没有必要避开它们。根据我的经验,重要的是测试的粒度和数量(更少的集成,更多的单元测试)。