
如何真正测试 UI
领先工程团队使用的测试技术

测试 UI 令人尴尬。用户期望频繁发布并包含各种功能。但每个新功能都会引入更多 UI 和新状态,然后您需要对其进行测试。每个测试工具都承诺“简单、稳定、快速”,但在细则中都有权衡。
领先的前端团队是如何跟上步伐的?他们的测试策略是什么,他们使用什么方法?我研究了 Storybook 社区中的十个团队,以了解哪些方法有效——Twilio、Adobe、Peloton、Shopify 等。
本文重点介绍了规模化工程团队使用的 UI 测试技术。这样,您就可以制定务实的测试策略,平衡覆盖率、设置和维护。在此过程中,我们将指出需要避免的陷阱。
我们在测试什么?
所有主要的 JavaScript 框架都是组件驱动的。这意味着 UI 是从“自下而上”构建的,从原子组件开始,并逐渐组合成页面。
请记住,UI 的每一部分现在都是一个组件。是的,包括页面。页面和按钮之间的唯一区别在于它们如何消耗数据。
因此,测试 UI 现在等同于测试组件。

当涉及到组件时,不同测试方法之间的区别可能很模糊。与其关注术语,不如让我们考虑 UI 的哪些特性值得测试。
- 视觉:给定一组 props 或状态,组件是否正确渲染?
- 组合:多个组件能否协同工作?
- 交互:事件是否按预期处理?
- 可访问性: UI 是否可访问?
- 用户流程:跨越多个组件的复杂交互是否有效?
您应该关注哪里?
全面的 UI 测试策略平衡了工作量和价值。但是,有很多测试方法,以至于在任何给定情况下都很难弄清楚什么才是正确的。这就是为什么许多团队使用以下标准来评估不同的测试技术。
- 💰 维护成本:编写和维护测试所需的时间和精力。
- ⏱️ 迭代速度:在进行更改和看到结果之间的反馈循环有多快。
- 🖼 真实环境:测试执行的位置——在真实浏览器中还是在 JSDOM 等模拟环境中。
- 🔍 隔离故障:测试失败时,您能多快确定故障源。
- 🤒 测试抖动:误报/漏报会使测试的意义消失。
例如,端到端测试模拟“真实”用户流程,但并非在所有地方都实用。在 Web 浏览器中进行测试的关键优势也是一个劣势。测试运行速度较慢,并且存在更多故障点(抖动!)。
现在我们已经涵盖了要测试的 UI 特性和评估每种测试方法的标准,让我们看看团队如何设计他们的测试策略。
"测试让我对自动依赖更新充满信心。如果测试通过,我们就合并它们。"
— Simon Taggart,Twilio 的首席工程师
视觉测试:这看起来对吗?
现代界面有无数种变化。变化的越多,就越难确认它们在用户的设备和浏览器上都正确渲染。
过去,您需要启动应用程序,导航到页面,并进行各种操作才能使 UI 进入正确的状态。

组件构造允许您将特定变体渲染为 props 和状态的函数。您无需启动整个应用程序即可查看组件的渲染方式,只需传入 props 和状态即可在隔离环境中查看它。
Twilio 和 Shopify 使用 Storybook 来隔离组件,模拟它们的变体,并将支持的测试用例记录为“故事”。这使得开发人员可以在初始开发期间以及在 QA 期间快速检查组件的外观。

尽管如此,考虑到应用程序的规模,手动测试 UI 外观是不切实际的。每次调整 UI 时,您都必须在每个断点和浏览器上检查每个组件的变体。这需要大量工作!
Auth0 和 Radix UI 自动化了 UI 验证过程。它们使用视觉测试在一个一致的浏览器环境中捕获每个 UI 组件的屏幕截图,包括标记、样式和其他资产。这样,它们就可以测试用户实际看到的内容。
每次提交时,都会自动将新屏幕截图与先前接受的基线屏幕截图进行比较。当机器检测到视觉差异时,开发人员会收到通知,以批准有意更改或修复意外错误。

但是 DOM 快照测试呢?评估 HTML 块的缺点已经广为流传。
值得吗?
总是。视觉测试的价值很高,但付出的努力很少。它们需要最少的维护工作,在真实浏览器中执行,并且抖动很少。
组合测试:这能协同工作吗?
当组件组合在一起时,常常会发生奇怪的事情。UI 由许多简单组件组成。验证这些组件如何集成可以确保整个系统正常工作。
但是,测试组合很棘手,因为复杂的功能通常与数据和应用程序状态相关联。这需要您模拟或仿真应用程序的业务逻辑。

BBC 和 Sidewalk Labs (Google) 使用 Storybook 在隔离环境中构建复合组件。Storybook 的插件简化了数据、事件和 API 响应的模拟。一旦您的 UI 在 Storybook 中隔离,您就可以进行视觉测试,以验证从组件到页面的所有内容的集成。



值得吗?
经常。这些测试需要一些投入,但它们会暴露难以追踪的微妙集成问题。
交互测试:当我按下这个按钮时会发生什么?
界面不是静态的。用户可以与 UI 交互,填写表单字段并触发事件。
如何确保 UI 对交互做出正确响应?我们可以使用计算机来模拟和验证用户交互!

一种方法是使用像Enzyme 这样的工具来访问组件的内部方法。然后触发状态更改并检查结果。这有效,但最终您是在测试内部工作,而不是像用户那样与 UI 交互。
这就是为什么大多数团队现在使用Testing-Library,因为它会评估组件的输出。它通过在虚拟浏览器 (JSDOM) 中渲染整个组件树来工作。它提供了模仿真实使用情况的实用程序。

Adobe 旨在更进一步,将组件用例编写为故事。然后,它们可以在 Jest 中重用,以运行交互测试。这得益于组件故事格式——一种基于 JavaScript ES6 模块的可移植格式。因此,允许您在开发过程中使用相同的故事,然后在视觉、组合和交互测试中使用。
值得吗?
有时。交互测试确保组件之间的连接正常工作。事件正在流动,状态正在更新。实际上,这意味着您通过编写维护成本相对较低的测试来获得中等覆盖率。
可访问性测试——应用程序对所有用户是否都可用?
您的用户以各种方式与 UI 交互。例如,使用鼠标、触摸屏、键盘和屏幕阅读器。可访问性是使网站对所有人可用的实践。

测试可访问性最准确的方法是手动检查多种浏览器、设备和屏幕阅读器。公司通常会聘请外部顾问或培训内部人员。但这可能不切实际,因为手动测试每次 UI 更改都非常耗时。因此,团队采用一种混合方法,结合手动测试和自动化。
作为第一道 QA 防线,使用机器来捕获明显的辅助功能违规。这通过针对一组最佳实践启发式(例如,使用Axe 这样的库)审计渲染的 DOM 来实现。在自动检查完成后,手动抽查 UI 以查找细微问题。
结合自动和手动测试最终达到了覆盖率和工作量的务实平衡。您将获得一个快速的反馈循环,可以在辅助功能问题影响生产之前发现并修复它们。大多数团队使用 Axe 对组件运行自动检查。这还使他们能够执行有针对性的测试以更快地发现错误。例如
- 原子组件:评估键盘可感知性、糟糕的颜色对比度或缺失的 aria 属性。
- 组合:验证组合组件不会阻碍彼此的行为。
- 页面:确保所有标题和各个部分按正确的顺序显示。

Twilio Paste 团队使用jest-axe 集成对组件运行自动可访问性审核。Axe 也可用作 Storybook 的插件。
值得吗?
总是。它不仅对用户有益,而且也是法律要求。Axe 是一个低投入的工具。使用它并不能自动使您的应用程序可访问,但它可以及早发现许多问题。
用户流程测试——您的应用程序是否可以端到端运行?
即使是最基本任务也需要用户完成一系列跨多个组件的步骤。这是另一个潜在的故障点。像Cypress 和Playwright 这样的工具允许您针对完整应用程序运行端到端 (E2E) 测试来验证这些交互。

测试完整应用程序需要大量的基础设施工作。您必须创建一个测试环境,该环境同时部署您系统的所有部分——前端、后端和其他服务。填充测试数据。然后连接到云浏览器以实际运行测试。
考虑到这些权衡,大多数团队选择放弃 UI 的全面 E2E 测试,而是偏爱交互和组合测试。或者,他们将自己限制在一小组 E2E 测试,以确保应用程序在部署到生产环境后仍然正常运行。
然而,对于一些团队来说,这种权衡是值得的。例如,O'Reilly 使用 Docker 来启动他们的整个基础设施。然后使用 Cypress 运行 E2E 测试来验证用户旅程。

值得吗?
零星使用。E2E 测试需要大量的权衡。它们提供了高度的信心,但需要花费时间和精力来启动和测试整个系统。因此,将 E2E 测试限制在关键用户流程,例如:注册 → 添加到购物车 → 购买。
自动化无聊的部分
如果您和我一样是开发者,构建 UI 比测试每种状态更有趣。那么,如何在测试每个功能的同时仍然有时间编写代码?
我采访的每个团队都使用持续集成 (CI) 服务器来减少手动工作量。每次推送代码时,CI 都会自动触发您的测试套件。测试在后台执行,结果会报告给 pull request,供大家审查。
自动 CI 检查会自动检测 UI 错误,让您在将 UI“外观和感觉”部署到生产环境之前充满信心。

您的 UI 测试策略
UI 测试是交付高质量体验不可或缺的一部分。确定务实的测试策略可能会令人困惑,因为应用程序的表面积很广,并且有很多方法可以对其进行测试。
您最终会在权衡中做出平衡。有些测试易于维护,但会提供虚假的保证。其他测试则评估整个系统,但速度很慢。
在采访了十个团队以确定哪些 UI 测试方法真正有效之后,我汇编了一个他们推荐的工具简短列表。
- 📚 Storybook 用于隔离组件与其上下文,从而简化测试。
- ✅ Chromatic 用于捕获原子组件中的视觉错误并验证组件组合/集成。
- 🐙 Testing Library 用于验证交互和底层逻辑。
- ♿️ Axe 用于审计可访问性
- 🔄 Cypress 用于跨多个组件验证用户流程
- 🚥 GitHub Actions 用于持续集成
下表总结了每种 UI 测试方法的优缺点以及它们的使用频率。
到目前为止,本文只是触及了 UI 测试的表面。在接下来的文章中,我将深入探讨测试堆栈的每一层,并详细介绍如何实施 UI 测试策略。订阅邮件列表,以便在发布更多测试文章时收到通知。
