- Selenium 是一个基于 W3C WebDriver 标准构建的成熟浏览器自动化库。
- Playwright 是一个较新的框架,包含自动等待、跟踪和测试运行程序。
- 对于新的网络项目,Playwright 通常可以更快地提高工作效率。
- 对于大型现有套件、更广泛的语言需求以及在真实供应商浏览器中进行测试,Selenium 仍然是一个不错的选择。
如果您正在开始一个测试自动化项目,Selenium 与 Playwright 问题很快就会出现。搜索结果可能会让事情听起来像是一个已解决的问题,但正确的答案取决于您的团队、您现有的测试以及您必须支持的浏览器。
本指南将它们与您在日常工作中实际感受到的事情进行了比较。代码示例显示了每个工具的典型风格,但我们在本文中并未运行它们。我们还避免引用速度百分比,因为发布的基准差异很大并且通常来自供应商。如果速度决定问题,请根据您自己的应用程序进行衡量。
简短的回答
对于大多数新的 Web 测试项目,请选择 Playwright,特别是如果您的团队可以使用 JavaScript、TypeScript、Python、Java 或 .NET 进行工作。您可以获得更多开箱即用的功能,并且可以减少基础设施和不稳定等待的时间。
如果您已经拥有大型工作套件,或者您需要 Playwright 未正式支持的语言(例如 Ruby),或者您必须在通过 Selenium 网格或设备云提供的真实浏览器版本和平台上进行测试,请选择 Selenium。
Selenium 与 Playwright 并肩作战
| 方面 | 硒 | 剧作家 |
|---|---|---|
| 首次发布 | 2004 | 2020 年,微软 |
| 它是什么 | 浏览器自动化库 | 框架,带有 Node.js 中的运行器 |
| 语言 | Java、Python、C#、Ruby、JavaScript | TypeScript、JavaScript、Python、Java、.NET |
| 浏览器 | Chrome、火狐、Edge、Safari | 铬、火狐、WebKit |
| 等待 | 显式等待你写 | 内置自动等待 |
| 测试跑者 | 带上你自己的,比如 pytest 或 JUnit | 包含 Node.js、Python 的 pytest 插件 |
| 并行运行 | Selenium Grid 或测试框架 | 内置于其跑步者中 |
| 调试 | 框架日志、您添加的屏幕截图 | 跟踪查看器、UI 模式、代码生成 |
| 网络嘲讽 | 有限的、通常是额外的工具 | 内置 |
| 社区 | 非常大且历史悠久 | 规模庞大且增长迅速 |
架构:每个人如何与浏览器对话
Selenium 使用 W3C WebDriver 协议(一种正式标准)发送命令。您的代码与控制浏览器的驱动程序(例如 ChromeDriver)对话,每个命令通常是一个单独的 HTTP 请求。由于浏览器供应商支持该标准,因此它具有广泛的兼容性。较新的协议 WebDriver BiDi 正在向标准添加双向通信和事件流。
Playwright 与浏览器保持持久连接,并使用自己的 Chromium、Firefox 和 WebKit 修补版本。由于连接是直接的双向连接,因此它可以对浏览器事件做出反应,并且每个测试都可以在自己的轻量级浏览器上下文中运行。这就是为什么大多数比较都认为 Playwright 更快,尽管实际差距取决于您的应用程序和测试。
对两种工具进行一次测试
这是用 Python 编写的针对公共实践站点的相同登录测试。
硒
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def test_login(driver):
driver.get("https://the-internet.herokuapp.com/login")
driver.find_element(By.ID, "username").send_keys("tomsmith")
driver.find_element(By.ID, "password").send_keys("SuperSecretPassword!")
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
message = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "flash"))
)
assert "You logged into a secure area" in message.text
您还需要一个固定装置来创建和关闭驱动程序,如我们在 Selenium Python 教程 中所示。
剧作家
from playwright.sync_api import Page, expect
def test_login(page: Page):
page.goto("https://the-internet.herokuapp.com/login")
page.get_by_label("Username").fill("tomsmith")
page.get_by_label("Password").fill("SuperSecretPassword!")
page.get_by_role("button", name="Login").click()
expect(page.locator("#flash")).to_contain_text("You logged into a secure area")
这依赖于 pytest-playwright 插件,它提供 page 夹具。它更短,主要是因为expect中内置了等待,并且像get_by_role这样的定位器以用户查看页面的方式描述了页面。使用 Selenium,您可以使用帮助程序和 页面对象模型 大大减少此样板文件,我们在任一工具中都推荐使用它。
等待和不稳定的测试
时间是造成浏览器测试不稳定的首要原因,也是这两种工具在日常使用中最不同的地方。
在 Selenium 中,您负责同步。显式等待效果很好,但必须有人在任何地方记住它们,而忘记的团队通常会求助于 time.sleep。我们的 Selenium waits 指南解释了如何正确执行此操作。
在 Playwright 中,操作会在执行操作之前自动检查元素是否可见、稳定、启用并能够接收事件。 Web 优先断言不断重试,直到超时。您仍然可以编写不稳定的测试,例如使用较差的测试数据,但默认情况下会处理问题的主要根源。
浏览器和语言
这就是 Selenium 真正的优势所在。 Playwright 的 WebKit 构建接近 Safari 的引擎,但它与 Mac 或 iPhone 上的 Safari 不同。如果真正的 Safari 行为至关重要,带有 SafariDriver 的 Selenium 或真正的设备云可以让您更接近用户实际运行的内容。
同样,Playwright 测试了其捆绑的浏览器版本,尽管它也可以驱动已安装的 Chrome 和 Edge 渠道。 Selenium 驱动您安装的浏览器,如果您必须支持特定版本,这会有所帮助。对于本机移动应用程序来说,这也不是完整的答案:基于 WebDriver 概念构建的 Appium 是常用工具。
在语言上,Selenium 官方支持 Ruby,并且在 Java 团队中拥有非常悠久的历史。 Playwright 的 Node.js 版本还拥有最完整的工具,因为那里有完整的测试运行程序。其他语言获得核心库并与自己的测试框架集成。
调试
剧作家在这里有明显的领先优势。它的跟踪查看器 记录每个操作,以及 DOM 快照、网络调用和控制台日志,因此您可以在 CI 运行完成后单步执行失败的操作。它的 UI 模式 和 codegen 也可以帮助您更快地编写测试。请参阅我们的 Playwright 初学者教程 了解如何使用它们。
使用 Selenium,您可以根据故障屏幕截图、浏览器日志、网格提供商的视频以及测试框架的报告自行组装。它运作良好,许多团队都有出色的设置,但需要努力构建。
网络和API功能
Playwright 可以用几行代码拦截和模拟网络请求,这对于测试错误状态很有用:
page.route("**/api/orders", lambda route: route.fulfill(status=500))
它还包括一个 API 请求客户端,因此您可以在驱动浏览器之前通过 API 创建测试数据。 Selenium 4 通过 Chrome DevTools 协议和 BiDi 添加了一些网络功能,但支持和便利性因浏览器和语言而异。许多 Selenium 用户添加代理或单独的 HTTP 库,如 API 测试 工具。
提示:无论您选择哪种工具,都应将浏览器测试集中在关键旅程上,并将详细信息降低到较低级别。较小的套件比更快的工具更重要。请参阅我们的端到端测试最佳实践。
并行运行和规模
Playwright 的运行程序通过简单的选项处理 CI 机器上的并行工作和分片。浏览器上下文很便宜,因此隔离不需要每次测试都使用全新的浏览器。
Selenium 使用 Selenium Grid 跨机器和浏览器版本分发测试,测试框架处理并行性。网格更多的是要运行,但它已经在非常大规模的情况下得到了验证,并且许多商业设备云直接支持它。
您应该从 Selenium 迁移到 Playwright 吗?
不是自动的。工作套件很有价值,重写会占用测试产品的时间。首先问这些问题:
- 是否存在可衡量的问题? 不稳定的测试或缓慢的调试都是很好的原因。 “它较新”不是。
- 套件有多大? 可以移动一百个测试。一万是一个重大工程。
- 您的页面对象干净吗? 良好的抽象使迁移成本大大降低。
- 您是否依赖 Selenium 特定的功能? 首先检查您的网格和设备需求。
如果你确实要移动,请逐渐移动。在 Playwright 中编写新测试,首先迁移最脆弱的旧测试,然后并行运行,直到旧套件小到足以退役。不要逐行翻译测试,因为这会延续睡眠和旧定位器。还要避免测试自动化错误中涵盖的错误。
如何选择
| 你的情况 | 合理选择 |
|---|---|
| 新的网络应用程序,现代化的团队 | 剧作家 |
| 大型稳定的 Selenium 套件 | 继续使用 Selenium,并改进它 |
| 团队编写 Ruby | 硒 |
| 真正的 Safari 覆盖范围至关重要 | Selenium,或设备云 |
| Flaky 测试和硬 CI 调试 | 尝试剧作家的试播集 |
| 本机移动应用程序 | 阿皮姆 |
最重要的是,进行一个简短的试点。在每个工具中针对您自己的应用程序、在您自己的 CI 中自动化您的三个最尴尬的旅程,并比较代码、速度以及调试故障的容易程度。一周的证据胜过任何比较文章,包括这篇文章。如果 Cypress 也在您的候选名单上,请阅读 Playwright vs Cypress。
最后的话
Playwright 通常是更容易开始的地方,而 Selenium 仍然是一个具有广泛影响力的可靠标准。两者都无法挽救设计不良的测试套件。根据您的实际限制进行选择,投资于稳定的定位器和良好的测试数据,并使您的套件专注于对用户最重要的事情。
常见问题
Playwright 比 Selenium 更好吗?
对于许多新的 Web 项目来说,是的,这要归功于自动等待和内置工具。 Selenium 更适合现有套件、更广泛的语言需求或特定的真实浏览器。
Playwright 比 Selenium 更快吗?
由于其持久的浏览器连接和轻量级上下文,它通常被报道为更快。真正的差异取决于您的应用程序,因此请根据您自己的测试来衡量。
硒已经过时了吗?
不会。Selenium 得到积极维护并基于 W3C 标准构建,并且仍然被广泛使用。 Selenium 4 和 WebDriver BiDi 继续对其进行现代化改造。
Playwright 可以测试真正的 Safari 吗?
Playwright 使用自己的 WebKit 版本进行测试,该版本与 Safari 的引擎很接近,但并不完全相同。对于真正的 Safari 或 iOS 行为,请使用真实设备或 SafariDriver。
初学者应该学习Selenium还是Playwright?
许多初学者发现 Playwright 更容易上手。硒仍然出现在许多职位列表中,因此请检查您当地的市场。核心概念在它们之间延续。
继续学习
需要测试、WordPress 或 SEO 方面的帮助?
我们帮助团队交付更好的软件并发展他们的网站。告诉我们您正在做什么,我们将建议明确的下一步。
更多指南 测试、人工智能和现代开发
喜欢这篇文章吗?选择一个主题并直接跳至我们最新的教程。
人工智能幻觉解释:语言模型为何会产生幻觉以及如何减少它
人工智能幻觉解释:它们是什么,为什么语言模型产生它们,常见类型,如何通过基础和提示来减少它们,以及我们进行的简单检查。
阅读文章 →DevOps环境变量解释:.env 文件、秘密和配置正确完成
使用我们运行的 Python 示例解释环境变量:读取和设置它们、为什么每个值都是字符串、.env 文件、进程继承、秘密和验证。
阅读文章 →软件开发API 速率限制解释:算法、标头和处理 429 错误
API 速率限制通过我们运行的模拟进行了解释:令牌桶、固定窗口、滑动窗口、429 响应、速率限制标头、带回退的重试和测试限制。
阅读文章 →测试自动化Python 中的模拟:unittest.mock、补丁以及导致测试谎言的错误
使用unittest.mock 在Python 中进行模拟,经过测试:模拟和return_value、side_effect、修补使用名称的位置、spec 和autospec、模拟日期以及常见错误。
阅读文章 →软件测试代码覆盖率解释:行覆盖率与分支覆盖率以及 100% 的真正含义
用真实的coverage.py运行来解释代码覆盖率:行、分支和条件覆盖率,阅读报告,为什么100%覆盖率仍然会错过错误,以及合理的目标。
阅读文章 →数据库与 SQLSQL 中的 DELETE、TRUNCATE 和 DROP:差异、回滚以及何时使用它们
DELETE、TRUNCATE 和 DROP 通过经过测试的 SQL 进行了解释:各自删除什么、回滚、触发器、身份重置、速度,以及 PostgreSQL、MySQL、SQL Server 和 SQLite 有何不同。
阅读文章 →数据库与 SQLSQL 视图解释:创建、使用和避免陷阱(附示例)
SQL 视图通过我们运行的查询进行解释:创建视图、实时结果、隐藏列、性能、可更新和物化视图、破坏的依赖关系和最佳实践。
阅读文章 →软件开发TypeScript 接口与类型:真正的差异,使用编译器进行测试
TypeScript 接口与类型,使用真实编译器进行检查:两者都可以做什么,只有一个可以做什么,声明合并,扩展与交集以及要遵循的简单规则。
阅读文章 →软件开发Python *args 和 **kwargs 解释:灵活的函数和清晰的示例
Python *args 和 **kwargs 用我们运行的代码进行了解释:打包和解包、参数顺序、仅关键字和仅位置参数、装饰器和常见错误。
阅读文章 →软件开发Python Lambda 函数:语法、实际用途以及何时不使用它们
Python lambda 函数用我们运行的代码进行了解释:语法、使用键排序、映射和过滤器、闭包、后期绑定陷阱,以及何时普通 def 是更好的选择。
阅读文章 →人工智能什么是人工智能代理?它们是如何工作的,只需运行一个简单的代理循环
什么是人工智能代理?关于代理循环、工具、内存和护栏的简单指南,以及我们运行的一个小型 Python 循环、真正的风险以及何时简单的聊天机器人是更好的选择。
阅读文章 →DevOps监控与可观察性:真正的区别,包括日志、指标和跟踪
监控与可观察性解释:已知和未知的故障、日志、指标和跟踪、检查事件演练、黄金信号、OpenTelemetry 和有用的警报。
阅读文章 →DevOpsDocker Volumes 与 Bind Mounts:以正确的方式保留容器数据
Docker 卷与绑定挂载解释:为什么容器数据消失、命名卷、绑定挂载、tmpfs、Compose 示例、备份、权限以及何时使用它们。
阅读文章 →测试自动化TDD 与 BDD:主要区别、以两种方式构建的一个功能以及何时使用每种方式
TDD 与 BDD 的解释是通过一种双向构建的折扣功能:使用我们运行的代码进行红绿重构、Given-When-Then 场景、工具、权衡以及何时使用每种方案。
阅读文章 →软件测试用户验收测试 (UAT):流程、清单和真实示例
用户验收测试解释:谁运行它、它与 QA 有何不同、七步流程、UAT 测试用例模板、清单、签核标准和常见错误。
阅读文章 →数据库与 SQLSQL NULL 值解释:IS NULL、COALESCE、NULLIF 和要避免的陷阱
通过我们运行的查询解释了 SQL NULL 值:三值逻辑、IS NULL、COALESCE、NULLIF,聚合、连接和排序如何处理 NULL,以及它悄悄引起的错误。
阅读文章 →数据库与 SQLSQL CASE WHEN 语句:语法、实例和常见错误
SQL CASE WHEN 解释了我们运行的查询:简单和搜索表单、条件顺序、SUM 透视、COUNT 技巧、自定义排序、更新和要避免的 NULL 陷阱。
阅读文章 →软件开发什么是智威汤逊?通过工作示例解释 JSON Web 令牌
什么是智威汤逊? JSON Web Tokens 解释:这三个部分,在我们运行的代码中构建和篡改的令牌,JWT 与会话,存储,刷新令牌和安全错误。
阅读文章 →软件开发JavaScript 事件循环解释:调用堆栈、微任务和计时器以及示例
JavaScript 事件循环用我们运行的代码进行了解释:调用堆栈、任务和微任务队列、为什么 setTimeout 0 不是立即执行、阻塞、饥饿和面试测验。
阅读文章 →软件开发Python 生成器和 Yield 解释:通过真实示例节省内存
Python 生成器和yield 用我们运行的代码进行了解释:它们如何暂停和恢复、测量内存节省、管道、无限序列、yield from、发送和常见陷阱。
阅读文章 →人工智能什么是嵌入?向量和余弦相似度简单解释
什么是嵌入?关于向量、余弦相似度和语义搜索的简单语言指南,其中包含我们运行的一个小示例、常见用途、选择模型和已知限制。
阅读文章 →DevOps蓝绿部署与金丝雀部署:差异、权衡以及如何选择
蓝绿部署与金丝雀部署解释:每种部署的工作原理、成本、风险和回滚、我们测试的稳定用户分桶、数据库迁移、滚动更新以及如何选择。
阅读文章 →测试自动化不稳定的测试:造成这些问题的原因以及如何彻底解决它们
我们运行的演示解释了不稳定的测试:主要原因、如何确认和诊断、正确的时间修复、共享状态和日期以及隔离过程。
阅读文章 →软件测试负载测试与压力测试:差异、指标和 k6 示例
负载测试与压力测试的解释:各自证明什么、峰值和浸泡测试、重要的指标、为什么平均值会误导、k6 个示例以及如何计划测试。
阅读文章 →软件测试测试用例与测试场景:主要区别、示例以及何时使用它们
测试用例与测试场景的解释:清晰的定义、并排的表格、从场景到案例的密码重置功能、模板以及何时使用每个功能。
阅读文章 →数据库与 SQLSQL 查询优化:读取执行计划并修复慢速查询(带计时)
对一百万行进行 SQL 查询优化测试:读取执行计划、添加正确的索引、修复不可控制的过滤器、使用复合索引和键集分页。
阅读文章 →数据库与 SQLSQL UNION 与 UNION ALL:差异、示例和性能测试
SQL UNION 与 UNION ALL 通过我们运行的查询进行了解释:重复、都遵循的规则、真实的数据错误、测量的性能、INTERSECT 和 EXCEPT 以及何时使用它们。
阅读文章 →软件开发JavaScript Fetch API 教程:GET、POST、错误处理和超时
针对本地服务器测试的 JavaScript Fetch API 教程:GET 和 POST、为什么不抛出 404、可重用的帮助程序、查询字符串、超时、CORS 和常见错误。
阅读文章 →软件开发Python 文件处理:读取、写入、CSV、JSON 和 pathlib 以及示例
使用我们运行的代码解释了 Python 文件处理:打开模式、使用、读取大文件、CSV、JSON、pathlib、二进制文件、安全写入、错误处理和常见错误。
阅读文章 →软件开发Python 类和对象:带有实际示例的 OOP 教程
用我们运行的代码解释 Python 类和对象:__init__、方法、类与实例属性、继承、属性、dunder 方法、数据类和常见错误。
阅读文章 →人工智能什么是大语言模型?法学硕士如何运作,在没有炒作的情况下进行解释
什么是大语言模型?法学硕士用简单的语言解释:标记、嵌入、注意力、训练、温度和上下文窗口、一个微小的下一个单词演示和真正的限制。
阅读文章 →DevOps适合初学者的 Linux 命令:带有示例的基本终端指南
适合初学者的 Linux 命令,按任务分组:导航、文件、查看日志、grep、管道、权限、进程和档案,并附有实用的日志分析示例。
阅读文章 →测试自动化Selenium 与 Playwright:主要区别、代码比较以及选择
Selenium 与 Playwright 比较:架构、等待、浏览器和语言支持、调试、两种工具中的相同测试、迁移建议以及如何选择。
阅读文章 →软件测试等价划分:通过实例解释测试设计技术
等效分区解释:如何找到有效和无效分区,年龄、密码和优惠券的工作示例,我们运行的测试,以及为什么将其与边界配对。
阅读文章 →软件测试软件测试中的严重性与优先级:差异、矩阵和实例
软件测试中的严重性与优先级解释:清晰的定义、带有示例的四向矩阵、级别尺度、谁设置每个级别以及如何运行错误分类。
阅读文章 →数据库与 SQLSQL 子查询教程:类型、相关子查询和 EXISTS 以及示例
SQL 子查询教程,其中包含我们运行的查询:标量、IN、FROM 和 SELECT 子查询、相关子查询、EXISTS、NOT IN NULL 陷阱以及子查询与 JOIN 与 CTE。
阅读文章 →数据库与 SQLSQL 事务和 ACID 解释:COMMIT、ROLLBACK 和隔离级别
SQL 事务和 ACID 通过我们运行的银行转账进行了解释:COMMIT、ROLLBACK、保存点、锁、隔离级别、脏读、死锁和最佳实践。
阅读文章 →软件开发Git merge 与 rebase 的区别:示例及如何选择
用真实的 log 输出、对比表、rebase 黄金法则和安全的团队工作流,讲清 Git merge 与 rebase 的区别。
阅读文章 →软件开发Python 列表推导式:语法、示例与何时避免使用
Python 列表推导式详解:语法、过滤、if-else、嵌套循环、实测耗时,以及何时普通 for 循环更合适。
阅读文章 →数据库与 SQLSQL JOIN 详解:附示例(INNER、LEFT、RIGHT、FULL)
通过示例表和查询,一步步讲解 SQL JOIN:INNER、LEFT、RIGHT、FULL、CROSS 和 SELF,并介绍常见错误与性能技巧。
阅读文章 →