不同类型的测试的名称在不同的代码库中往往有共同的主题,但它们没有特别严格的定义。本课程提供了一些关于每种类型测试含义的指南,但其他资源可能会提供不同的定义。
在之前的页面中,已经有单元测试和组件测试(在我们的示例中,指的是 React 组件)的示例。我们可以将这两者都放在我们的测试金字塔(或其他形状!)的较低位置,因为它们复杂度较低且运行速度快,但可能不如更复杂的集成测试实用。

常见的测试类型
单元测试
单元测试是范围最小的测试。它们通常用于测试小部分代码,或纯粹的无状态代码,几乎以数学方式进行测试:如果我为你的代码提供输入 X、Y 和 Z,其输出应该是 A、B 和 C。
具有单元测试的代码通常不会有外部依赖项,例如从网络获取数据或隐式使用任何其他函数或库。它是你可以“切出”并单独测试的代码树节点。
虽然单元测试往往编写和运行速度很快,但始终有可能测试小单元的代码不会提供有用的信息。通常,代码单元缺乏与其他代码的交互意味着你最好在更高的级别进行测试以降低风险。
组件测试
对于 web 开发者来说,“组件”这个名称被重载了,通常意味着用户可见的组件,例如 React 组件或 Web 组件。其更通用的定义是一个可测试的工作块,例如,一个具有外部依赖项的类。为了有效地进行测试,此组件必须将其依赖项模拟或跳过。
由于现代 web 开发实践以组件的概念为基础,因此组件测试是考虑测试的一种实用方法:例如,你可能会决定每个组件都需要一个测试。在单个开发者或小团队对组件声明明确所有权的情况下,组件测试也很容易跟进。但是,模拟复杂的依赖项可能很困难。
集成测试
这些测试倾向于一起测试一小群组件、模块、子系统或其他有意义的代码部分,以确保它们正常工作。这是一个非常模糊的定义。对于 web 开发者来说,想象一下你正在测试的代码不是你站点的真实生产版本(甚至不接近),但仍然连接了你系统的各种相关组件。
这甚至可能包括“真实”的依赖项,例如测试模式下的外部数据库,而不是纯粹的模拟。例如,你的集成测试可以确认测试数据库中有东西,而不是说 query()
将始终返回相同的两个条目。数据本身不太重要,但你现在正在测试是否可以成功连接和查询数据库。
编写相对简单的集成测试是可能的,这些测试具有广泛的含义,可以使用断言进行检查,因为连接到各种组件的单个操作可能会导致一系列可衡量的效果。因此,集成测试可以有效地证明你的复杂系统将按预期运行。但是,它们可能难以编写和维护,并且可能会引入不必要的复杂性。例如,为集成测试编写 FakeUserService
会增加 FakeUserService
和 RealUserService
都必须实现 UserService
的要求。
冒烟测试
这些测试应该非常快速地完成,并确定你的代码库是否处于合理状态。在实践中,这主要意味着对对你的体验有广泛影响的代码执行简单测试。
例如,在一个大型已登录 web 应用程序中,这可能是确保登录和身份验证系统正常工作,因为如果没有它,应用程序将无法使用,并且进一步的测试是无关紧要的。
在大型代码库中,冒烟测试可能是你的 package.json 的 test
脚本下运行的良好候选者。手动测试也可以充当一种冒烟测试。
回归测试
回归测试是一种冒烟测试,用于确保在新版本或其他功能开发之后,现有功能继续工作,或者不会重新引入旧的错误。
这与测试驱动开发 (TDD) 的概念相关。为显式触发错误而编写的测试用例,以及稍后用于确保错误已修复的测试用例,都算作回归测试用例,因为它们的存在应防止同一错误再次出现。
然而,回归测试可能是一个没有完美解决方案的问题。这是一个经常被业务需求引用的术语:随着功能的开发,重要的是旧功能不会中断。一个经过良好测试的代码库应该能够维护这一点,但真实的代码库并不总是能达到理想状态。这将在以后的章节中详细介绍。
可视化测试
可视化测试涉及拍摄网站状态的屏幕截图或视频,以便将已知的良好状态(例如之前的屏幕截图)与当前的测试运行进行比较。就其性质而言,它需要运行真实的浏览器,以便它可以渲染 HTML、CSS 和网站的其他部分。
与其可视化测试运行你的整个代码库的端到端测试,不如构建 HTML“线束”来仅渲染某些组件,尤其是在不同的屏幕尺寸中以触发自适应 UI,这可能很有用。这比纯粹使用 JSDOM 或类似框架更复杂。
可视化测试失败可能是其他类型中断的良好信号。但是,复杂的 UI 可能会因与你尝试测试的功能无关的原因而导致可视化测试失败,例如其他新功能更改了 UI 的外观,甚至新操作系统版本渲染表情符号的方式与早期版本不同。
端到端测试
端到端测试通常位于测试金字塔的顶部。它们描述了与你的 web 应用程序或网站的完整体验交互,可能以特定功能为中心,并且它们通常在由 WebdriverIO、Selenium 或 Puppeteer 等代理控制的浏览器内运行,这些代理可以或多或少地像在生产环境中部署一样运行你的代码库(尽管它们通常在 localhost 上提供服务)。
根据你的站点,这可能涉及以测试用户身份登录、执行主要操作以及确认你的站点或系统处于正确的状态。我们将在后面的章节中介绍更多此类测试的示例,因为它们可能非常强大,但有时难以维护。
简化它们的一些策略可以包括缩小它们的范围,或在相关时模拟特定的组件。例如,如果用户需要登录你的站点,但登录不是你正在测试的功能,你可能需要为测试环境设置一个标志,允许测试控制器在不登录或创建关联 cookie 的情况下充当用户。
尽管端到端测试可能是跨代码库的巨大横截面进行测试的非常强大的方法,但如此大规模的测试由于其对外部系统的依赖性,可能会有缺陷或不可靠。例如,如果每个测试都创建或修改一个条目,它们也常常会在你的数据库中留下大量测试数据。累积像这样的剩余数据会使你难以确定测试是如何失败的。
API 测试
API 测试可以指确认你的软件提供的 API 的行为,或访问真实世界(可能是实时的)API 以确认其行为。无论哪种方式,这都倾向于测试系统之间的抽象——它们最终将如何相互通信——而实际上没有像集成测试中那样将它们集成在一起。
这些测试可以提供集成测试的基本先导,而无需运行你正在测试其连接的系统的开销。但是,对真实世界系统的测试可能会有缺陷。
其他类型
根据你的来源,还有各种其他可能有用的测试方法。有趣的例子包括以下内容
- 手动测试。
- 验收测试,一种由敏捷开发推广的手动测试,确认产品“满足用户的需求”。
- 混沌测试是指输入随机数据以查看会发生什么,以确保站点在输入错误数据时不会崩溃。
- 故障测试有意模拟复杂系统中的故障,例如网络故障,以确保被测代码以受控方式响应。
- 构建测试确认代码库的构建工件可以生成,方法是检查它们是否存在或它们的内容是什么。这种测试类型对于检查复杂 CMS 的输出可能很有用。
代码覆盖率
可以衡量你的代码中有多少百分比通过自动化测试进行了测试,并随着时间的推移将其报告为统计数据。我们不建议以 100% 的代码覆盖率为目标,因为这可能会导致不必要的开销,以及简单化或设计不良的测试,这些测试无法深入涵盖主要用例。
覆盖率本身也可以在编写或处理测试(尤其是集成测试)时成为一个有用的工具。通过显示百分比或单行代码细分单个测试测试的代码,你可以深入了解缺少什么或接下来可以测试什么。
资源
检查你的理解
以下哪些是已知的测试类型?