Python+Playwright 自动化测试实战指南
1. 为什么选择 Python + Playwright?从零开始的自动化测试之旅
如果你正在为Web应用的测试工作感到头疼,比如每天要重复点击几十次相同的按钮,或者每次上线前都要手动验证十几个页面的功能,那么自动化测试就是你的“救星”。而在众多自动化工具中,Python + Playwright 的组合,是我这几年用下来感觉最“香”的一个。它不像一些老牌工具那样配置复杂,也不像纯代码方案那样需要写大量底层逻辑。Playwright 给我的感觉就像是一个“开箱即用”的智能助手,你告诉它“去那个页面点一下登录按钮”,它就能完美执行,而且几乎不会出错。
我最初是从 Selenium 转过来的,最大的感受就是 Playwright 的等待机制太聪明了。以前用 Selenium,最烦的就是要到处写 time.sleep(5),页面加载慢一点或者元素出现晚一点,脚本就报错了。Playwright 内置了自动等待,它会智能地等待元素变得可点击、可输入,我们再也不用去猜页面什么时候加载完了。这对于测试现代那些大量使用 JavaScript 动态加载内容的单页应用(SPA)来说,简直是福音。另一个让我决定深入使用的点是它的“超能力”——一个API搞定所有浏览器。Chromium、Firefox、WebKit(Safari的内核),你写一套脚本,可以同时在三种浏览器引擎上跑,这对于确保网站在不同浏览器下的兼容性太重要了。
那么,谁适合学习这个呢?我觉得覆盖面很广。如果你是测试工程师,想从手工测试转向自动化,提升效率和覆盖面,Playwright 上手快,能快速产出价值。如果你是后端或全栈开发,想给自己写的功能加一层自动化验收测试,Playwright 的 Python API 非常直观,能和你的开发流程无缝集成。甚至如果你是运维同学,需要定时检查线上页面的可用性,用它写个监控脚本也特别方便。总之,只要你的工作和网页打交道,并且厌倦了重复劳动,这套组合就值得一试。
2. 手把手搭建你的第一个 Playwright 测试环境
万事开头难,但 Playwright 的开头真的不难。我们一步步来,确保你的环境干干净净、稳稳当当。
2.1 Python 环境的准备与检查
Playwright 的 Python 包需要 Python 3.7 或更高版本。我建议直接用 Python 3.8 或 3.10,这两个是长期支持版本,社区支持好,不容易遇到奇怪的兼容性问题。怎么检查呢?打开你的命令行(Windows 上是 CMD 或 PowerShell,Mac/Linux 上是终端),输入 python --version 或者 python3 --version。如果看到了类似 Python 3.10.12 的输出,那就没问题。
如果没安装 Python,去官网下载安装包,安装时务必记得勾选 “Add Python to PATH” 这个选项,这能让你在命令行里直接使用 python 命令,省去后续很多配置的麻烦。安装好后,我强烈建议创建一个虚拟环境来管理这个项目的依赖。这就像给你的项目一个独立的“房间”,里面的包怎么装、装什么版本,都不会影响到你电脑上其他的 Python 项目,避免版本冲突。创建虚拟环境很简单:
# 进入你的项目目录
cd your_project_folder
# 创建虚拟环境,环境文件夹叫 venv
python -m venv venv
创建好后,需要激活它:
- Windows (CMD):
venv\Scripts\activate.bat - Windows (PowerShell):
venv\Scripts\Activate.ps1(可能需要先执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser来允许脚本执行) - Mac/Linux:
source venv/bin/activate激活后,你的命令行提示符前面通常会显示(venv),表示你已经在这个独立的环境里了。
2.2 安装 Playwright 核心包与浏览器驱动
环境准备好了,安装 Playwright 本身只是一条命令的事:
pip install playwright
这条命令会从 PyPI(Python的包仓库)拉取最新的 playwright 包。我建议在这里加一个 -i 参数使用国内镜像源,速度会快很多,比如 pip install playwright -i https://pypi.tuna.tsinghua.edu.cn/simple。
安装完 Python 包,Playwright 还需要它自己配套的浏览器来执行操作。这些浏览器是经过特别定制的版本,和你在网上下载的 Chrome 或 Firefox 略有不同,它们集成了更好的自动化控制接口。安装它们同样是一条命令:
playwright install
这条命令会下载 Chromium、Firefox 和 WebKit 三个浏览器的二进制文件。第一次运行可能会花点时间,因为它要下载几百兆的文件,请保持网络通畅。这里有个小技巧:如果你只想安装其中一个浏览器(比如只做 Chrome 测试),可以用 playwright install chromium。全部安装完成后,你的环境就彻底准备好了。你可以通过 playwright --version 来查看安装的 Playwright 命令行工具和浏览器驱动版本,确保一切就绪。
3. 编写你的第一个自动化测试脚本:从截图开始
理论说再多,不如动手跑一遍。我们来写一个最简单的脚本,感受一下 Playwright 的流畅。
3.1 同步模式:最直观的入门方式
新建一个文件,比如叫 first_test.py。Playwright 提供了同步和异步两种 API。对于初学者,我强烈建议从同步 API 开始,它的代码是顺序执行的,读起来就像在看操作说明书,非常直观。我们在文件里写入以下代码:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# 1. 启动浏览器。headless=False 表示我们能看到浏览器界面
browser = p.chromium.launch(headless=False)
# 2. 打开一个新的标签页
page = browser.new_page()
# 3. 导航到目标网址
page.goto("https://www.bing.com")
# 4. 给当前页面截个图,保存为 bing_homepage.png
page.screenshot(path="bing_homepage.png")
# 5. 关闭浏览器
browser.close()
保存文件后,在命令行(确保还在虚拟环境里)运行 python first_test.py。你会看到一个 Chromium 浏览器窗口自动打开,访问必应首页,然后闪退,同时在你脚本的同目录下生成一张 bing_homepage.png 的图片。恭喜你,第一个自动化脚本成功了!sync_playwright() 这个上下文管理器帮你处理了驱动的启动和清理,browser 对象代表浏览器,page 对象代表一个标签页,大部分操作都在 page 上完成。把 headless=False 改成 headless=True 再试试,你会发现浏览器不再弹出,直接在后台默默完成了截图,这就是无头模式,适合在服务器或持续集成(CI)环境中运行。
3.2 异步模式:应对高并发与高性能场景
如果你的测试场景需要同时操作多个页面,或者你的应用本身就是异步的(比如用 asyncio 的 Web 框架),那么异步 API 会更适合。它能让你的测试脚本在等待网络响应或页面加载时,去执行其他任务,效率更高。我们把上面的脚本改写成异步版本:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
# 注意这里多了 await 关键字
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto("https://www.bing.com")
await page.screenshot(path="bing_async.png")
await browser.close()
# 运行异步主函数
asyncio.run(main())
代码结构很相似,主要变化是:async with 替代 with,函数前加了 async def,所有可能耗时的操作前都加了 await 关键字。运行方式是一样的:python first_test_async.py。对于新手,可以先熟练掌握同步 API,等需要处理复杂并发测试时,再切换到异步模式。我个人的经验是,80% 的日常自动化任务,同步模式完全够用,而且写起来更省心。
4. 玩转核心 API:像真人一样操作网页
只会截图可不够,自动化测试的核心是模拟用户交互。Playwright 提供了一套极其丰富的 API,几乎能覆盖所有用户操作。
4.1 精准的元素定位与交互
要让脚本点击一个按钮或输入文字,首先得告诉它“操作哪个元素”。Playwright 支持多种定位器(Locator),最常用的是 CSS 选择器和文本定位。假设我们要测试一个登录页面:
page.goto("https://example.com/login")
# 使用 CSS 选择器定位用户名输入框,并输入文本
page.fill("input[name='username']", "my_username")
# 定位密码框并输入
page.fill("input[type='password']", "my_password")
# 定位登录按钮并点击
page.click("button:has-text('登录')")
# 或者使用更精确的 CSS 选择器
# page.click("#login-button")
page.fill() 方法会先清空输入框再输入文本,非常方便。page.click() 会模拟真实的点击事件。除了 fill 和 click,还有 check() 勾选复选框,select_option() 选择下拉框,hover() 鼠标悬停等等。这里有个关键点:Playwright 的定位器是“懒”评估且智能的。当你写 page.locator("button") 时,它并不会立刻去页面上找,而是在你执行操作(如 .click())时,才去查找,并且它会自动等待这个元素出现、变得可见且可操作。这大大减少了因页面加载延迟导致的失败。
4.2 智能等待与导航控制
等待是自动化测试的玄学,但 Playwright 把它变成了科学。我们应尽量避免使用固定的 page.wait_for_timeout(3000),因为网络快慢不确定,固定等待要么浪费时间,要么导致失败。应该使用条件等待:
# 等待页面标题出现特定文字
page.wait_for_url("**/dashboard") # 等待URL变化
# 等待某个元素出现在DOM中
page.wait_for_selector(".welcome-message", state="visible")
# 甚至等待一个网络请求完成
page.wait_for_response("**/api/user/profile")
导航控制也很简单:
page.goto("/home") # 跳转
page.go_back() # 点击浏览器后退按钮
page.go_forward() # 点击前进按钮
page.reload() # 刷新页面
这些操作都内置了等待,直到导航成功(或失败)才会继续执行下一行代码。
4.3 捕获页面状态:截图、PDF 与内容断言
测试不仅仅是操作,还要验证结果。截图我们见过了,page.screenshot(path="full_page.png", full_page=True) 这个 full_page 参数可以截取整个滚动页面的长图,非常实用。对于 Chromium,你还能直接把页面保存为 PDF:page.pdf(path="report.pdf"),用来生成测试报告很棒。
更常见的验证是断言页面内容:
# 断言标题包含特定文字
assert "Dashboard" in page.title()
# 获取元素文本内容进行断言
welcome_text = page.text_content(".welcome")
assert welcome_text == "Hello, John!"
# 断言元素是可见的
assert page.is_visible("text=操作成功")
# 获取输入框的值进行验证
username_value = page.input_value("#username")
assert username_value == "my_username"
把这些断言和之前的操作结合起来,一个完整的测试用例就诞生了。
5. 解锁高级技巧:让测试更强大、更稳定
掌握了基础操作,我们来点“高级货”,这些功能能让你的测试脚本应对更复杂的场景,也更贴近真实用户行为。
5.1 模拟移动设备与创建独立上下文
现在很多网站都有移动端适配,我们需要测试移动端视图。Playwright 内置了主流设备的配置信息,可以轻松模拟:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# 获取 iPhone 13 的设备描述符
iphone_13 = p.devices["iPhone 13"]
# 创建一个新的浏览器上下文,并应用设备模拟
browser_context = browser.new_context(**iphone_13)
# 在这个上下文中打开新页面
mobile_page = browser_context.new_page()
mobile_page.goto("https://m.example.com")
mobile_page.screenshot(path="iphone_view.png")
browser_context(浏览器上下文)是个非常强大的概念。它相当于一个独立的浏览器会话,拥有独立的 cookies、本地存储和缓存。你可以用它来实现多用户同时测试,或者让每个测试用例都在一个干净的环境中运行,互不干扰。
5.2 拦截和 Mock 网络请求
这是 Playwright 的王牌功能之一。有时候我们不想依赖不稳定的后端服务进行测试,或者想测试一些边界情况(如接口返回错误)。这时可以拦截请求并返回模拟数据:
# 定义一个路由处理函数
def handle_route(route):
# 拦截请求,并返回一个自定义的JSON响应
route.fulfill(
status=200,
content_type="application/json",
body='{"success": true, "data": "mocked"}'
)
# 在跳转页面之前,设置路由拦截规则
page.route("**/api/getUserInfo", handle_route)
page.goto("https://example.com/profile")
# 此时页面发起的 /api/getUserInfo 请求将不会到达真实服务器,而是收到我们的模拟数据
这个功能对于前端测试来说简直是神器,可以轻松构造各种测试数据,测试加载状态、错误提示等。
5.3 使用 Codegen 录制脚本:不会写代码也能开始
如果你对选择器不熟悉,或者想快速生成一个复杂操作的脚本草稿,一定要试试 Playwright 的录制功能。在命令行运行:
playwright codegen https://example.com/login
这会同时打开两个窗口:一个浏览器和一个代码生成器。你在浏览器里的所有操作(点击、输入、滚动)都会实时转换成 Python(或其他语言)代码,显示在代码生成器窗口中。你可以直接复制这些代码到你的编辑器里。虽然生成的代码可能不够优化(比如选择器可能不够稳健),但它是一个绝佳的起点,能帮你快速理解 API 的使用方法。
6. 融入开发生命周期:调试、集成与实战
脚本写好了,怎么让它真正用起来,并且好用呢?这里分享一些工程化实践。
6.1 高效的调试技巧
调试自动化脚本,最怕的就是“一闪而过,不知道发生了什么”。这里有几个我常用的方法:
- 慢动作播放:在启动浏览器时加入
slow_mo参数,让每个操作都以慢速执行,方便你观察。browser = p.chromium.launch(headless=False, slow_mo=1000) # 每个操作间隔1秒 - 打开开发者工具:配合无头模式,可以直接把浏览器自带的 DevTools 打开。
browser = p.chromium.launch(headless=False, devtools=True) - 详细的日志:设置环境变量
DEBUG=pw:api,可以在控制台看到 Playwright 内部详细的 API 调用日志,对于排查复杂问题非常有用。 - 遇到失败时暂停:在集成 pytest 时,可以使用
pytest --pdb选项,在测试失败时进入调试器,检查当时的页面状态。
6.2 与 Pytest 集成:构建标准化测试套件
单独运行脚本只是第一步,用专业的测试框架来组织用例才是正道。pytest 是 Python 生态里最流行的测试框架,和 Playwright 搭配得天衣无缝。首先安装插件:
pip install pytest-playwright
这个插件提供了有用的 Fixture,比如 page。创建一个测试文件 test_login.py:
import pytest
def test_login_success(page):
"""测试登录成功流程"""
page.goto("https://example.com/login")
page.fill("#username", "correct_user")
page.fill("#password", "correct_pwd")
page.click("button[type='submit']")
# 断言跳转到了首页
page.wait_for_url("**/home")
assert page.is_visible("text=Welcome back")
def test_login_failure(page):
"""测试登录失败提示"""
page.goto("https://example.com/login")
page.fill("#username", "wrong_user")
page.fill("#password", "wrong_pwd")
page.click("button[type='submit']")
# 断言错误提示信息出现
assert page.is_visible("text=Invalid username or password")
然后使用 pytest 命令运行,并指定浏览器:
pytest test_login.py --browser chromium --headed
pytest-playwright 插件会自动管理浏览器的启动和关闭,并为每个测试用例提供一个全新的 page 对象,保证测试隔离性。你还可以轻松地生成 HTML 报告、并行运行测试,把自动化测试完全融入你的 CI/CD 流水线。
6.3 实战中踩过的坑与避坑指南
最后,分享几个我实际项目中遇到的“坑”,希望能帮你少走弯路。
- 选择器稳定性:尽量避免使用依赖于页面结构顺序的 CSS 选择器,比如
div:nth-child(3) > button。一旦前端改了点样式,测试就挂了。优先使用有明确语义的data-testid属性,让前端同学给关键测试元素加上,比如<button data-testid="login-submit">,然后你用page.click("[data-testid=login-submit]")来定位,这是最稳健的方式。 - 处理动态内容与 iframe:对于动态加载的内容,一定要用
wait_for_selector等待,而不是假设它已经存在。对于 iframe 内的元素,你需要先获取frame对象:frame = page.frame(name="iframe-name"),然后在frame上进行操作:frame.fill("input", "value")。 - 处理文件下载:Playwright 可以很好地监听下载事件。但要注意,无头模式下文件会下载到特定位置,你需要通过监听
page.on(“download”)事件来获取文件路径和进行后续验证。 - 性能与资源:虽然 Playwright 很快,但浏览器实例本身是资源消耗大户。在 CI 环境中大量并行运行测试时,要注意内存消耗。及时关闭不需要的
browser_context和page,使用browser_context.close()和page.close()。对于一套完整的测试套件,合理规划测试用例的顺序和浏览器的复用策略,能显著提升执行效率。
环境搭好了,脚本会写了,高级功能也了解了,剩下的就是结合你的具体业务场景,去设计和实现那些能真正解放你双手的自动化测试了。记住,好的自动化测试不是一蹴而就的,从最重要的、最重复的用例开始,慢慢积累,逐步构建起你的测试堡垒。
更多推荐



所有评论(0)