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

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

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

一个带有两个抽屉的橱柜,您可以同时打开这两个抽屉。

接下来,您将学习如何做到这一点。本文将介绍如何将这些测试类型组合成合理的策略,并选择适合您项目的策略。

您可以将这些策略与多种形状进行比较,以便更好地理解其含义。以下是各种策略及其各自的规模和开发范围。

应用大小 团队构成 依赖手动测试 测试策略
小 仅限开发者 高 测试冰淇淋甜筒
测试螃蟹
小 开发者和质量保证工程师 高 测试冰淇淋甜筒
测试螃蟹
小 仅限开发者 低 测试金字塔
大 仅限开发者 高 测试奖杯
测试钻石
大 开发者和质量保证工程师 高 测试奖杯
测试螃蟹
大 仅限开发者 低 测试奖杯
测试 Honeycomb

我们来详细了解一下这些策略,并了解其名称背后的含义。

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

在开始制定良好的策略之前,请先确定测试目标。您认为应用在什么情况下才算经过了充分测试?

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

作为开发者,您还会使用许多其他应用和设备。在这方面,您是依赖所有这些系统“正常运行”的用户。反过来,您也依赖无数开发者尽最大努力让他们的应用和设备正常运行。作为开发者,您也努力不辜负这份信任。因此,您的首要目标始终应该是交付可正常运行的软件并为用户提供服务。这也适用于您为确保应用质量而编写的测试。Kent C. Dodds 在其针对前端应用的静态测试、单元测试、集成测试和端到端测试一文中对此进行了很好的总结:

测试与软件使用方式越相似,测试结果就越可靠。

作者:Kent C. Dodds

Kent 将其描述为“在测试中获得信心”。选择合适的测试类型,让测试更贴近用户,测试结果就越可靠。换句话说,您在金字塔中攀登得越高,就会越自信。不过,金字塔是什么?

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

第一步,确定您需要检查哪些要求,以确保它们得到满足。了解应使用哪些测试类型,以及在何种详细程度下,您可以在保持高效成本结构的同时获得最高的置信度。许多开发者会通过类比来探讨这个主题。以下是最常见的几种,首先是众所周知的经典类型。

金字塔、菱形、冰淇淋甜筒、蜂窝和奖杯等多种形状,代表测试策略。

经典:测试金字塔

当您开始寻找测试策略时,您可能会首先看到测试自动化金字塔。Mike Cohn 在其著作《Succeeding with Agile》中介绍了这一概念。后来,Martin Fowler 在其实用测试金字塔一文中对这一概念进行了扩展。您可以将金字塔直观地表示为:

测试金字塔。

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

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

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

  3. 端到端测试(也称为界面测试)。这些测试会模拟真实用户及其互动。此类测试需要更多时间来执行,因此费用更高。他们处于金字塔的顶端。

置信度与资源

如前所述,各层的顺序并非偶然。这些图表显示了优先级和相应的费用。这样,您就可以清楚地了解应该为每个层编写多少测试。您在测试类型的定义中已经看到了这一点。

由于端到端测试最贴近用户,因此它们能让您最确信应用是否按预期运行。不过,它们需要完整的应用堆栈和模拟用户,因此也可能是成本最高的。因此,置信度与执行测试所需的资源之间存在直接竞争关系。

测试金字塔,其中箭头显示了不同测试类型所需的置信度和资源的方向。

测试金字塔试图通过让您更加专注于单元测试并严格确定 E2E 测试所涵盖用例的优先级来解决此问题。例如,最重要的用户体验历程或最容易出现缺陷的地方。正如 Martin Fowler 所强调的,Cohn 金字塔中最重要的两点如下:

  1. 编写不同粒度的测试。
  2. 级别越高,测试数量应该越少。

金字塔进化了!测试金字塔的调整

多年来,讨论一直围绕着金字塔展开。金字塔似乎过度简化了测试策略,忽略了许多测试类型,并且不再适用于所有实际项目。因此,它可能会产生误导。金字塔是否已变形? Guillermo Rauch 对此有自己的看法:

编写测试。数量不超过上限。主要是集成。

作者:Guillermo Rauch

这是关于此主题最常被引用的名言之一,我们来拆解一下:

  • “编写测试”。这不仅能建立信任,还能节省维护时间。
  • “不多”。100% 的覆盖率并不总是好事,因为这样一来,您的测试就没有优先级,并且会有很多维护工作。
  • “Mostly integration”(主要集成)。这里再次强调集成测试:它们具有最高的业务价值,既能让您每天都保持较高的置信度,又能保持合理的执行时间。

这会让您重新思考测试金字塔,并将重点转移到集成测试。过去几年中,人们提出了许多调整方法,下面我们来看看最常见的方法。

测试钻石

第一个调整是,不再像测试金字塔那样过分强调单元测试。假设您已达到 100% 的单元测试覆盖率。不过,下次重构时,您必须更新许多此类单元测试,并且可能会想要跳过这些测试。所以它们会受到侵蚀。

因此,再加上对集成测试的更高关注,可能会出现以下形状:

测试钻石。

金字塔演变为菱形。您可以看到之前的三个层,但尺寸不同,并且单位层已被剪切:

  • 单位。按照您之前定义的方式编写单元测试。不过,由于这些测试往往会失效,因此请优先考虑并仅涵盖最关键的情况。
  • 集成。您所熟悉的集成测试,用于测试单个单元的组合。
  • E2E。此层负责处理界面测试,类似于测试金字塔。请注意,仅针对最关键的测试用例编写 E2E 测试。

测试蜂巢

Spotify 引入了另一种改编形式,它与测试菱形类似,但更适合基于微服务的软件系统。测试蜂巢是另一个视觉类比,用于说明要为基于微服务的软件系统编写的测试的粒度、范围和数量。由于微服务规模较小,其最大的复杂性不在于服务本身,而在于它与其他服务的交互方式。因此,微服务的测试策略应主要侧重于集成测试。

测试蜂巢。

这种形状让我们想起了蜂巢,因此得名。它包含以下层:

  • 集成测试。Spotify 的文章引用了 J. B. Rainsberger 的定义来定义此层:“根据另一个系统的正确性来判断通过或失败的测试。”此类测试具有您需要考虑的外部依赖项,相反,您的系统也可能是破坏其他系统的依赖项。与其他类似测试中的 E2E 测试一样,请谨慎使用这些测试,仅在最重要的情况下使用。
  • 集成测试。与其他适配一样,您应重点关注此层。它包含一些测试,这些测试以更隔离的方式验证服务的正确性,但仍与其他服务结合使用。这意味着测试还会涵盖其他一些系统,并重点关注交互点,例如通过 API 测试。
  • 针对实现细节的测试。这些测试类似于单元测试,即专注于自然隔离且具有自身内部复杂性的代码部分的测试。

如果您想详细了解此测试策略,请参阅 Martin Fowler 撰写的比较测试金字塔与蜂窝模型的帖子以及 Spotify 的原始文章。

测试奖杯

您已经可以看到对集成测试的反复强调。不过,您在上一篇文章中遇到的另一种类型在理论上不属于测试,但仍然是您在测试策略中应考虑的一个重要方面。测试金字塔和您目前看到的大多数改编版本中都缺少静态分析。测试奖杯模型在考虑静态分析的同时,仍将重点放在集成测试上。测试奖杯源自 Guillermo Rauch 的早期名言,由 Kent C. Dodds:

测试奖杯。

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

  • 静态分析。它在这个类比中扮演着至关重要的角色,让您只需运行已经概述的调试步骤,就能捕获拼写错误、样式错误和其他 bug。
  • 单元测试。它们可确保您的最小单元得到适当测试,但测试奖杯不会像测试金字塔那样强调它们。
  • 集成。这是主要关注点,因为它能以最佳方式平衡成本和更高的置信度,与其他调整方式一样。
  • 界面测试。包括端到端测试和视觉测试,它们位于测试奖杯的顶部,类似于它们在测试金字塔中的角色。

如需详细了解测试奖杯,请参阅 Kent C. 的博文。Dodds 的文章。

一些更侧重于界面的方法

这些方法都很好,但无论您将策略称为“金字塔”“蜂窝”还是“钻石”,都仍然缺少一些东西。虽然自动化测试很有价值,但请务必记住,手动测试仍然必不可少。自动化测试应减轻日常任务负担,让质量保证工程师能够专注于关键领域。自动化测试不应取代手动测试,而应作为其补充。有没有办法将手动测试与自动化测试相结合,以获得最佳结果?

测试冰淇淋甜筒和测试螃蟹

测试金字塔确实有两种变体,它们更侧重于这些以界面为中心的测试方式。这两种方法都具有高置信度的优势,但由于测试作业速度较慢,因此成本自然更高。

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

测试用蛋卷冰淇淋。

冰淇淋甜筒模型更侧重于手动测试或界面测试,而最不侧重于单元测试。在开发者开始工作时对测试策略只有一些想法的项目中,这种模式通常会形成。冰淇淋代码被视为一种反模式,这不无道理。它在资源和人工方面成本高昂。

测试螃蟹与测试冰淇淋甜筒类似,但更侧重于端到端测试和视觉测试:

测试螃蟹。

此测试策略还包含一个方面:验证应用功能和外观是否正常。测试螃蟹强调了视觉测试的重要性,上一篇文章中对此进行了定义。集成测试(分为组件测试和 API 测试)进一步退居幕后,而单元测试在这里扮演的角色更加次要。如需详细了解此测试策略,请参阅这篇关于测试螃蟹的文章。

虽然这两种测试策略的成本较高,但它们也有其适用场景:例如,在需要较少测试或需要涵盖的复杂性较低的小型项目中。在这种情况下,专注于集成测试的全面测试策略可能过于复杂。

虽然这两种测试策略的成本较高,但它们也有其适用场景,例如在需要较少测试且不需要涵盖大量复杂性的较小项目中。在这种情况下,专注于集成测试的全面测试策略可能过于复杂。

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

现在,您已经了解了最常见的测试策略。您从经典的测试金字塔开始,了解了它的许多变体。现在,您需要根据自己的产品对这些方法进行评估,并确定哪种方法最适合您的项目。这个问题的答案应该以大家最喜欢的“视情况而定”开头。但这并不影响其准确性。

这需要视情况而定。

从上述测试策略(甚至未提及的策略)中选择最合适的策略取决于您的应用。它应该适合您的架构、您的要求,最后但同样重要的是,适合您的用户及其要求。所有这些可能因应用而异。这完全正常。请记住,您的首要目标是服务用户,而不是死守教科书式的定义。

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

[…] 编写富有表现力的测试,这些测试应建立清晰的边界、快速可靠地运行,并且仅在有用的原因下失败。

作者:Justin Searls

专注于报告用户可能遇到的实际错误的测试,不要偏离目标。测试的设计应以用户为中心,而不仅仅是为了达到 100% 的覆盖率,或争论各种测试类型的比例。

专注于报告用户可能遇到的实际错误的测试,不要偏离目标。测试的设计应以用户为中心,而不仅仅是为了达到 100% 的覆盖率,或引发关于特定测试类型应占多少比例的争论。