Stefan Judis 2022-10-20
UI 应该像 API 一样被认真监控。Checkly 的 Stefan Judis 解释了微软开源的 Playwright 是如何做到这一点的。
你有多确定你的网站此刻正在正常运行?
我相当确信我的项目是在线的,但我始终有一种隐藏的担忧——那些我尚未察觉的生产环境问题。
因为事情总会出错,而且常常悄无声息地发生。
当然,高覆盖率且自动化的测试确实有所帮助,但说起来容易做起来难,因为构建一个稳定可靠的测试套件本身就是一项挑战。
我应该写哪些测试?单元测试?端到端测试?我应该测试 API,还是测试使用这些 API 的应用程序?或者两者都要测?此外,这些测试又该在何时、何地运行呢?
我没有所有问题的答案,因为和软件工程一样,测试领域也没有“银弹”。这始终是一个权衡取舍的问题。
不过,在从事 Web 开发十年之后,让我分享一下我是如何应对测试难题的,以及我当前首选的工具。
Playwright —— 一款现代化的端到端测试解决方案
在我职业生涯的大部分时间里,我曾是一位狂热的“100% 单元测试覆盖率”倡导者。但如今,我更倾向于从用户体验出发进行端到端测试。即使有上千个经过单元测试的组件,一旦它们组合在一起时出现问题,也毫无意义。而端到端测试则能确保所有部分协同工作无误。
然而,我的端到端测试之路可谓坎坷。早期我使用过 Selenium、PhantomJS 和 CasperJS,却始终难以构建稳定的测试套件,最终只得到了一堆不可靠、频繁误报的系统。
Puppeteer、Cypress 等现代工具确实是巨大的进步,但有一个工具在开发者社区中讨论得还不够多。
让我告诉你,为什么微软开源的 Playwright 是这个领域中被低估的“黑马”!
跨浏览器、跨语言、跨平台
首先,Playwright 是“全能型选手”。

控制所有现代浏览器渲染引擎:Chromium(Chrome/Edge)、WebKit(Safari)和 Gecko(Firefox)。
同时,Playwright 是跨平台的。你可以在 Windows、macOS、Linux、CI 环境或本地运行它。
最后,Playwright 还支持多种编程语言。你可以用自己最熟悉的语言编写测试:TypeScript、JavaScript、Python、.NET 或 Java 均受支持。
这三点已经构成了坚实的基础,但在选择测试方案时,还有至少两个关键因素需要考虑:速度和开发者体验。
让我们深入探讨!
一个为节省时间而生的测试框架
如果你依赖自动化测试,你将不断创建新的测试用例。每一个新增的测试都会拖慢整个测试套件的执行速度,因为需要运行更多的代码。当测试套件变得过于缓慢时,它就会成为交付流程中的负担。一旦慢到一定程度,开发人员就只会“在需要时”才运行它们。我就经历过这种情况,相信我,那一刻你就已经失败了。
请务必关注你的测试执行时间,否则你无法成功。
但 Playwright 在速度方面能带来哪些不同呢?
使用 DevTools 协议控制浏览器
Playwright 利用 Chrome DevTools 协议直接与浏览器通信。相比其他替代方案,该协议能实现更快、更稳定的执行效果。虽然每次可能只节省零点几秒,但积少成多!
自动等待、可操作性检查与 Web 优先断言
端到端测试通常包含大量 waitFor 语句。例如:点击一个按钮,然后等待某个元素出现;提交表单后,等待新页面加载。在端到端测试中,总有些东西需要等待。
令人耳目一新的是,等待机制已内置于 Playwright 本身。诸如点击元素或填写输入框等 UI 操作会自动等待。
假设你想点击一个在某个 UI 操作后才出现的按钮;传统做法是先执行 UI 操作,再等待按钮出现,最后点击它。
而在 Playwright 中,你只需“直接”点击该按钮,省去显式的等待步骤。框架会自动等待该元素变为“可操作”状态——即:元素已存在于 DOM 中、可见、未处于动画状态、已启用,且未被其他元素遮挡。
// 当按钮变为可操作状态时点击它
await page.click('[data-test=cta]')
这种自动等待机制极大地简化了 UI 测试,让你可以专注于行为验证,而不是编写等待逻辑。但这还不是全部!
Playwright 团队还将自动等待机制集成到了其断言库中。Web 优先断言看起来像是一些便捷方法,但实际上远不止如此。
来看一个例子:
// 等待 .status 元素的文本变为 “Submitted”
await expect(page.locator('.success')).toHaveText('You made it!');
上述断言会查询一个 DOM 元素,并检查其文本是否为 “Submitted”。但这个断言并非一次性检查。“expect” 会不断重试该检查,直到条件满足或超时。
虽然这看似微不足道,但它能显著简化代码,因为你无需再操心元素何时达到特定状态。忘掉那些手动编写的 waitFor 语句,让 Playwright 自动处理其余部分!
自动等待是一种绝佳的方式,可避免因随机超时而浪费时间,并编写出最精简的测试代码。但如果这还不够,你的测试套件仍然慢得无法接受怎么办?
并行化,再并行化!
Playwright 支持测试并行化,可在多个编排好的操作系统进程(工作进程)中运行测试。你只需配置要启动的工作进程数量,定义哪些测试可以并行运行,然后就可以高枕无忧了。虽然设置非常简单,但并行化能极大提升测试速度。
快速执行只是故事的一半,那开发者体验又如何呢?
运行、录制与调试
虽然 Playwright 主要是一个命令行工具,但它配备了一些实用的“辅助应用”,以简化复杂的端到端测试任务。
录制并调试你的脚本
编写新测试很耗时,这时代码生成器就派上用场了。只需运行一条 CLI 命令,即可开始录制下一个端到端测试的基础脚本。
npx playwright codegen playwright.dev
该命令会打开一个浏览器窗口和 Playwright Inspector。你在浏览器中的操作(如点击链接或填写表单)会被记录下来,并生成对应的脚本。录制完成后,你可以复制该脚本,调整选择器、添加断言,然后将其整合到你的代码库中。
但 Inspector 不仅在创建新脚本时有用。当你需要调试现有脚本以找出测试失败原因时,它同样大显身手。调试模式提供了一种简单的方式来逐步执行浏览器脚本。Playwright 会高亮显示选中的元素,让你更容易定位问题所在。
但也许你更喜欢在 IDE 中工作?Playwright 同样为你考虑周全。
强大的 VS Code 扩展
如果你不想额外运行其他应用程序,可以安装 Playwright 的 VS Code 扩展,直接在 VS Code 中调试、录制和运行测试代码。

以上涵盖了本地测试的创建与调试,但如果脚本在你的机器上运行良好,却在其他环境中失败,又该怎么办呢?
通过追踪功能“穿越时空”
为了调试远程环境中失败的脚本,Playwright 提供了追踪(tracing)功能。生成的 zip 归档文件可通过另一条 CLI 命令或 Playwright 的在线追踪查看器进行分析。你会看到一个时间轴、所有执行指令,以及失败测试的截图。
收到失败测试的通知后,下载追踪文件,就能清楚地了解发生了什么。没有什么比这种“时光倒流”更棒的了!
借助所有这些工具开发测试,能带来卓越的开发体验。接下来呢?
何时何地运行你的测试?
有了现代化的测试工具,最后一个关键问题依然存在:你应在何时运行测试,以确保整个技术栈正常运行?
理想情况下,开发团队应遵循 DevOps 原则,覆盖功能开发、交付和测试全流程。你的自动化测试套件至少应在每次部署时于 CI/CD 流水线中运行,以避免回归问题。对新生产环境部署进行测试,是获得基本信心的最低要求。但如何才能达到 100% 的信心呢?
开发者因测试而来,因监控而留
我意识到,仅在部署时运行测试并不能为我所有的项目提供足够的信心。来看两个例子:
设想一个没有运行时计算的静态 Jamstack 站点。根据其设计,这类技术栈出错的可能性较低。因此,仅在部署时进行测试可能就足够了。
但另一方面,考虑一个涉及定期数据库更新、用户生成数据以及多个第三方服务集成的系统。这类项目的潜在错误来源呈指数级增长。仅靠部署驱动的测试显然不够。
业界普遍做法是监控 API 以满足可用性 SLA(服务等级协议)。那么,为什么我们不以同样的标准来监控 UI 呢?你是否经常遇到某些服务声称其 API 可用性高达 99.999%,但其 Web 产品却频频出现故障?我见过太多这样的情况。
因此,本文的核心观点是:UI 应该像支撑它的 API 一样被认真监控,才能交付最佳产品。产品应始终进行端到端测试!
像 Checkly 这样的工具扩展了 Playwright 的能力,使你不仅能测试部署,还能监控整个技术栈。使用 Playwright 对你的站点进行端到端测试——无论是在本地、部署时,还是按计划定期运行。提高标准,确保系统随时正常运行。
测试真正重要的内容,交付卓越的产品!
唯一重要的是产品能稳定运行,不出意外。问题必须在进入生产环境前就被发现,像我这样的开发者也应彻底消除对生产问题的持续恐惧。
测试领域正经历巨大变革。Playwright 以及其他新兴测试解决方案,是迈向交付更优质软件的重要一步。因此,如果你尚未对产品进行端到端测试,也许今天就是开始的最佳时机!相信我,端到端测试已经今非昔比,它是实现 100% 发布信心的正确之道。终于!