测试运行位置

自动化测试通常可以通过手动运行脚本或使用测试框架中的辅助程序(通常称为测试运行程序)来查找和运行测试。不过,您可能并不总是希望必须手动运行脚本。有多种方法可以运行测试,这些方法可以在开发生命周期的不同阶段提供反馈和信心。

先决条件脚本

Web 项目通常有一个配置文件,即 package.json 文件,该文件由 npm、pnpm、Bun 或类似工具设置。此配置文件包含项目的依赖项和其他信息,以及辅助脚本。这些辅助脚本可能包括如何构建、运行或测试您的项目。

package.json 中,您需要添加一个名为 test 的脚本,用于描述如何运行测试。这很重要,因为当使用 npm 或类似工具时,“test”脚本具有特殊含义。此脚本可以仅指向一个引发异常的单个文件,例如 node tests.js,但我们建议使用它来指向已建立的测试运行程序。

如果您使用 Vitest 作为测试运行程序,则您的 package.json 文件将如下所示

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

运行带有此文件的 npm test 会运行 Vitest 的默认测试集一次。在 Vitest 中,默认是查找所有以“.test.js”或类似名称结尾的文件并运行它们。根据您选择的测试运行程序,命令可能略有不同。

在本课程的示例中,我们选择使用 Vitest,这是一个越来越流行的测试框架。您可以在Vitest 作为测试运行程序中阅读有关此决定的更多信息。但是,重要的是要记住,测试框架和运行程序(即使跨语言)往往具有通用的术语。

手动测试调用

在您积极处理代码库时,手动触发自动化测试(例如,使用前面示例中的 npm test)可能很实用。在开发功能的同时为其编写测试可以帮助您了解该功能应如何工作,这涉及到测试驱动开发 (TDD) 的概念。

测试运行程序通常会有一个简短的命令,您可以调用该命令来运行部分或全部测试,并且可能有一个监视器模式,该模式会在您保存测试时重新运行测试。这些都是在开发新功能时非常有用的选项,它们旨在使编写新功能、其测试或两者都变得容易,并提供快速反馈。例如,Vitest 默认在监视器模式下运行:vitest 命令将监视更改并重新运行它找到的任何测试。我们建议在您编写测试时在另一个窗口中保持打开状态,以便您可以在开发测试时获得有关测试的快速反馈。

一些运行程序还允许您在代码中将测试标记为 only。如果您的代码包含 only 测试,则只有这些测试会在您运行测试时触发,从而使测试开发更快、更易于排除故障。即使您的所有测试都快速完成,使用 only 也可以减少您的开销并消除运行与您正在处理的功能或测试无关的测试的干扰。

对于小型项目,尤其是只有一个开发人员的项目,您可能还希望养成定期运行代码库的整个测试套件的习惯。如果您的测试很小并且完成速度很快(所有测试在几秒钟内完成),这将特别有帮助,这样您可以确保在继续之前一切正常工作。

在预提交或审核过程中运行测试

许多项目选择在将代码合并回其 main 分支时确认代码库是否正常运行。如果您是测试新手,但过去曾为开源项目做出贡献,您可能已经注意到拉取请求 (PR) 过程的一部分确认项目的所有测试都通过了,这意味着您的激动人心的新贡献没有对现有项目产生负面影响。

如果您在本地运行测试,则项目的在线存储库(例如,GitHub 或其他代码托管服务)将不知道您的测试是否通过,因此将测试作为预提交任务运行可以向所有贡献者明确表明一切正常运行。

例如,GitHub 将这些称为“状态检查”,您可以通过 GitHub Actions 添加它们。GitHub Actions 从根本上来说是一种测试:每个步骤都必须成功(不失败或抛出 Error)才能使操作通过。您可以将 Actions 应用于项目的所有 PR,并且项目可以要求 Actions 在您贡献代码之前通过。GitHub 的默认 Node.js 操作运行 npm test 作为其步骤之一。

A screenshot of a GitHub
  Actions test process.
GitHub Actions 测试过程的屏幕截图。

这种测试方法试图通过不接受未成功运行测试的代码来确保您的代码库始终为“绿色”。

作为持续集成的一部分运行测试

一旦您的绿色 PR 被接受,大多数代码库会再次基于项目的 main 分支而不是之前的 PR 运行测试。这可能会立即发生,也可能会定期发生(例如,每小时或每晚)。这些结果通常显示为持续集成 (CI) 仪表板的一部分,该仪表板显示项目的整体运行状况。

此 CI 步骤可能看起来是多余的,特别是对于小型代码库的项目而言,测试在审核期间已通过,因此更改后也应该通过。但是,情况并非总是如此!即使在成功产生绿色结果后,您的测试也可能突然失败。导致这种情况的一些原因包括

  • 一次接受了多个更改(有时称为竞争条件),并且它们以微妙的、未经测试的方式相互影响。
  • 您的测试不可重现,或者它们测试“不稳定”的代码,它们可能会在没有代码更改的情况下通过和失败。
    • 如果您依赖于代码库外部的系统,则可能会发生这种情况。对于代理,想象一下测试 Math.random() > 0.05,这将随机失败 5% 的时间。
  • 有些测试对于每个 PR 来说都过于昂贵或耗时,例如端到端测试(有关此内容的更多信息,请参阅自动化测试的类型),并且它们可能会随着时间的推移而中断,但并非总是发出警报。

这些问题并非不可能克服,但值得意识到的是,测试和一般的软件开发永远不会是一门精确的科学。

关于回滚的插曲

当测试作为持续集成的一部分运行时,甚至当测试作为状态检查的一部分运行时,构建最终可能会处于“红色”状态,或另一种意味着测试失败的状态。如前所述,发生这种情况的原因有很多,包括测试提交时的竞争条件或不稳定的测试。

对于较小的项目,您的直觉可能是将其视为危机!停止一切,回滚或恢复有问题的更改,并恢复到已知的良好状态。这可能是一种有效的方法,但重要的是要记住,测试(以及一般的软件!)是达到目的的手段,而不是目的本身。您的目标可能是编写软件,而不是使所有测试都通过。相反,您可以向前滚动,在破坏性更改之后进行另一项更改以修复失败的测试。

另一方面,您可能已经看到或参与过长期处于中断状态的大型项目。或者更糟糕的是,大型项目有一个不稳定的测试,该测试经常中断,足以引起开发人员的警报疲劳。这通常是领导者需要解决的存在问题:这些测试甚至可能被关闭,因为它们被视为“妨碍开发”。

对此没有快速的解决方案,但它可以帮助您更有信心地编写测试(提升技能)并缩小测试范围(简化),以便可以更轻松地识别故障。增加组件测试集成测试的数量(有关类型,请参阅自动化测试的类型)可以比一个难以维护且试图一次完成所有事情的巨大端到端测试提供更多信心。

资源

检查您的理解情况

npm 和类似程序在测试时查找的特殊脚本名称是什么?

检查
测试
预提交
验证