金字塔还是螃蟹?找到适合的测试策略

了解如何将不同的测试类型组合成合理的策略,以匹配您的项目。

欢迎回来!上一篇文章奠定了关于如何处理不同测试类型及其包含内容的大量基础,并阐明了测试类型定义。还记得这张小小的表情包图片吗?您可能想知道您了解的所有这些测试类型如何协同工作。

A cupboard with two drawers you can open at the same time.

接下来,您将确切地了解这一点。本文介绍了如何将这些测试类型组合成合理的策略,并选择一种适合您项目的策略。

您可以将这些策略比作多种形状,以便更好地理解它们的含义。以下是具有各自大小和开发范围的策略列表。

应用程序规模 团队构成 对手动测试的依赖程度 测试策略
小型 仅限开发者 测试冰淇淋筒
测试螃蟹
小型 开发者和质量保证工程师 测试冰淇淋筒
测试螃蟹
小型 仅限开发者 测试金字塔
大型 仅限开发者 测试奖杯
测试钻石
大型 开发者和质量保证工程师 测试奖杯
测试螃蟹
大型 仅限开发者 测试奖杯
测试蜂巢

让我们仔细看看这些策略,并了解它们名称背后的含义。

确定测试目标:您希望通过这些测试实现什么目标?

在开始构建良好的策略之前,请先确定您的测试目标。您认为什么时候您的应用程序已经过充分测试?

在测试方面,实现高测试覆盖率通常被开发者视为最终目标。但这总是最佳方法吗?在决定测试策略时,可能还有另一个需要考虑的关键因素——满足用户的需求。

作为一名开发者,您也使用许多其他应用程序和设备。在这方面,您是用户,您依赖所有这些系统“正常工作”。反过来,您依赖无数开发者尽最大努力使其应用程序和设备正常工作。反过来,作为一名开发者,您也努力不辜负这种信任。因此,您的首要目标始终应该是交付可用的软件并为用户服务。这延伸到您编写的用于确保应用程序质量的测试。Kent C. Dodds 在他的前端应用程序的静态测试、单元测试、集成测试和 E2E 测试对比文章中很好地总结了这一点

您的测试越类似于您的软件的使用方式,它们就越能给您带来信心。

Kent C. Dodds

Kent 将其描述为在测试中获得信心。您选择的测试类型越贴近用户,您就越能信任您的测试能够获得有效的结果。换句话说,您在金字塔中爬得越高,您就越有信心。但是等等,金字塔是什么?

确定测试策略:如何选择测试策略

第一步,确定您需要检查哪些需求部分以确保它们得到满足。找出要使用的测试类型,以及在哪个详细程度级别上,您可以在保持高效成本结构的同时获得最大的信心。许多开发者使用类比来处理这个主题。以下是最常见的类比,从广为人知的经典类比开始。

A lot of shapes like pyramid, diamonds, ice cone, honeycombs and a trophy; representing test strategies.

经典类比:测试金字塔

一旦您开始寻找测试策略,您可能会首先遇到测试自动化金字塔这个类比。Mike Cohn 在他的著作《敏捷开发实践》中介绍了这个概念。后来,Martin Fowler 在他的实用测试金字塔文章中扩展了这个概念。您可以将金字塔可视化为以下形状

The test pyramid.

如图所示,测试金字塔由三个层组成

  1. 单元测试。您会在金字塔的底层找到这些测试,因为它们执行速度快且易于维护。它们是隔离的,并且针对最小的测试单元。例如,请参阅针对非常小的产品的典型单元测试

  2. 集成测试。这些测试位于金字塔的中间层,因为它们具有可接受的执行速度,但比单元测试更贴近用户。集成测试的一个示例是 API 测试。您也可以将组件测试归为此类型。

  3. E2E 测试(也称为 UI 测试)。这些测试模拟真实用户及其交互。此类测试需要更多时间来执行,因此成本更高。它们位于金字塔的顶层。

信心与资源

如前所述,各层的顺序并非巧合。它们显示了优先级和相应的成本。这让您清楚地了解每层应该编写多少个测试。您已经在测试类型的定义中看到了这一点。

由于 E2E 测试最贴近您的用户,因此它们为您提供最大的信心,确信您的应用程序按预期工作。但是,它们需要完整的应用程序堆栈和模拟用户,因此,它们也可能是最昂贵的。因此,信心与执行测试所需的资源直接竞争。

The test pyramid with arrows showing the direction of confidence and resources required for different testing types.

金字塔试图通过让您更专注于单元测试并严格优先考虑 E2E 测试涵盖的案例来解决这个问题。例如,您最重要的用户旅程或最容易出现缺陷的地方。正如 Martin Fowler 强调的那样,Cohn 金字塔中最重要的两点如下

  1. 编写具有不同粒度的测试。
  2. 您获得的级别越高,您应该拥有的测试就越少。

金字塔的演变!测试金字塔的变体

多年来,讨论一直围绕着金字塔展开。金字塔似乎过度简化了测试策略,遗漏了许多测试类型,并且不再适合所有真实世界的项目。因此,它可能具有误导性。金字塔是否已经变形?Guillermo Rauch 对此有看法

编写测试。不要太多。主要是集成测试。

Guillermo Rauch

这是关于此主题最常被引用的名言之一,因此让我们对其进行分解

  • “编写测试”。不仅因为它建立信任,而且因为它节省了维护时间。
  • “不要太多”。100% 的覆盖率并不总是好的,因为那样您的测试没有优先级,并且会有大量的维护工作。
  • “主要是集成测试”。再次强调集成测试:它们具有最高的业务价值,通过在保持合理的执行时间的同时,每天为您提供高度的信心水平。

这让您再次思考测试金字塔,并将您的重点转移到集成测试。在过去几年中,已经提出了许多变体,因此让我们看看最常见的变体。

测试钻石

第一个变体消除了对单元测试的过度强调,正如在测试金字塔中看到的那样。想象一下,您已经在单元测试中达到了 100% 的覆盖率。但是,下次您重构时,您将不得不更新许多这些单元测试,并且您可能会试图跳过它们。因此,它们会逐渐失效。

因此,并且随着对集成测试的更高关注,可能会出现以下形状

The test diamond.

金字塔演变成钻石。您可以看到之前的三个层,但尺寸不同,并且单元测试层已被削减

  • 单元测试。按照您之前的定义编写单元测试。但是,由于它们容易失效,因此请优先考虑并仅覆盖最关键的案例。
  • 集成测试。您知道的集成测试,测试单个单元的组合。
  • E2E 测试。此层处理 UI 测试,类似于测试金字塔。请注意,仅为最关键的测试用例编写 E2E 测试。

测试蜂巢

还有另一个变体,由 Spotify 引入,它类似于测试钻石,但更专门用于基于微服务的软件系统。测试蜂巢是另一个可视化类比,用于说明 基于微服务的软件系统要编写的测试的粒度、范围和数量。由于微服务体积小,微服务中最显著的复杂性不在于服务本身,而在于它与其他服务的交互方式。因此,微服务的测试策略应主要侧重于集成测试。

The testing honeycomb.

这种形状让我们想起蜂巢,因此得名。它具有以下层

  • 集成测试。Spotify 的文章引用了 J. B. Rainsberger 的一句话来定义这一层:“一个测试,其通过或失败取决于另一个系统的正确性。”此类测试具有您需要考虑的外部依赖项,相反,您的系统可能是一个依赖项,会破坏其他系统。与其他类比中的 E2E 测试类似,请谨慎使用这些测试,仅用于最必要的案例。
  • 集成测试。与其他变体类似,您应该专注于这一层。它包含验证您的服务在更隔离的方式下但仍与其他服务组合在一起的正确性的测试。这意味着测试还将包括一些其他系统,并侧重于交互点,例如,通过 API 测试。
  • 关于实现细节的测试。这些测试类似于单元测试——侧重于代码中自然隔离的部分的测试,因此具有其自身的内部复杂性。

如果您想了解有关此测试策略的更多信息,请参阅 Martin Fowler 的将测试金字塔与蜂巢进行比较的文章以及 Spotify 的原始文章

测试奖杯

您已经可以看到对集成测试的重复关注。但是,您在上一篇文章中遇到的另一种类型不是理论上的测试,但仍然是您应该在测试策略中考虑的重要方面。在测试金字塔和您迄今为止看到的大多数变体中,都缺少静态分析。测试奖杯变体考虑了静态分析,同时保持了对集成测试的关注。测试奖杯源自 Guillermo Rauch 早期的引言,由 Kent C. Dodds 开发

The testing trophy.

测试奖杯是一个类比,以稍微不同的方式描述了测试的粒度。它有四层

  • 静态分析。它在这个类比中起着至关重要的作用,让您可以通过仅运行已概述的调试步骤来捕获错别字、样式错误和其他错误。
  • 单元测试。它们确保您的最小单元得到适当的测试,但测试奖杯不会像测试金字塔那样强调它们。
  • 集成测试。与其他变体一样,这是主要重点,因为它以最佳方式平衡了成本和更高的信心。
  • UI 测试。包括 E2E 测试和可视化测试,它们位于测试奖杯的顶部,类似于它们在测试金字塔中的作用。

要了解有关测试奖杯的更多信息,请参阅 Kent C. Dodds 关于此主题的博客文章

更多以 UI 为中心的方法

这一切都很好,但无论您如何称呼您的策略,“金字塔”、“蜂巢”还是“钻石”,仍然缺少一些东西。虽然测试自动化很有价值,但重要的是要记住,手动测试仍然至关重要。自动化测试应减轻例行任务,并使质量保证工程师能够专注于关键领域。自动化不应取代手动测试,而应补充它。有没有一种方法可以将手动测试与自动化集成以获得最佳结果?

测试冰淇淋筒和测试螃蟹

实际上,测试金字塔的两个变体更侧重于这些以 UI 为中心的测试方式。两者都具有高信心的优势,但由于测试执行速度较慢,因此自然成本更高。

第一个是测试冰淇淋筒,看起来像倒置的金字塔。如果没有手动测试步骤,它也称为测试披萨。

The testing ice cone.

冰淇淋筒更侧重于手动或 UI 测试,而最不侧重于单元测试。它通常在开发者仅对测试策略进行少量思考就开始工作的项目中成形。冰淇淋筒被认为是反模式,这是理所当然的。它在资源和手动工作方面成本很高。

测试螃蟹类似于测试冰淇淋筒,但更强调 E2E 测试和可视化测试

The testing crab.

此测试策略包含另一个方面:它验证您的应用程序功能是否正常且外观良好。测试螃蟹突出了可视化测试的重要性,这在上一篇文章中定义过。集成测试(分为组件测试和 API 测试)进一步退居次要地位,而单元测试在这里起着更次要的作用。您可以在这篇关于测试螃蟹的文章中找到有关此测试策略的更多详细信息。

虽然这两种测试策略成本更高,但它们也有其用武之地:例如,在需要较少测试或需要覆盖较少复杂性的小型项目中。在这种情况下,专注于集成测试的成熟测试策略可能过于复杂。

尽管这两种测试策略成本较高,但它们也有其用武之地,例如,在需要较少测试且不需要覆盖大量复杂性的小型项目中。在这种情况下,专注于集成测试的全面测试策略可能是不必要的复杂。

实用建议:让我们制定策略!

您现在已经了解了最常见的测试策略。您从经典类比——测试金字塔开始,并了解了它的许多变体。现在您需要评估它们对您的产品的影响,并决定哪种策略最适合您的项目。这个问题的答案应该以每个人最喜欢的“视情况而定”开头。但这并不会降低它的准确性。

It depends.

从所描述的策略(甚至包括遗漏的策略)中选择最合适的测试策略取决于您的应用程序。它应该适合您的架构、您的需求,以及最后但并非最不重要的,您的用户及其需求。所有这些都可能因应用程序而异。这完全正常。请记住,您最重要的目标是为用户服务,而不是教科书式的定义。

通常,现实世界中的测试很难单独分离和定义。即使 Martin Fowler 本人也强调了不同定义的积极方面,例如在单元测试的情况下。正如 Justin Searls他的推文中正确指出的那样

[…] 编写具有表现力的测试,建立清晰的边界,快速可靠地运行,并且仅因有用的原因而失败。

Justin Searls

专注于报告用户可能遇到的实际错误的测试,不要从您的目标中分心。测试的设计应使用户受益,而不仅仅是提供 100% 的覆盖率,或争论应该编写哪种测试类型的百分比。

专注于报告用户可能遇到的真实错误的测试,不要从您的目标中分心。测试的设计应使用户受益,而不仅仅是提供 100% 的覆盖率,或引发关于您应该编写哪种特定测试类型的百分比的争论。