我用 Claude Code + Playwright MCP 跑通了第一次真实 UI 测试
我用 Claude Code + Playwright MCP 跑通了第一次真实 UI 测试
以前编写 UI 自动化测试,通常需要先分析页面、寻找元素、编写定位器,再组织测试流程。
这一次,我尝试把测试任务直接交给 Claude Code,让它通过 Playwright MCP 操作真实浏览器,完成页面识别、登录和商品信息获取。
本文记录完整实践过程,包括:
- 如何配置并验证 Playwright MCP
- 如何把测试需求描述给 Claude Code
- Claude Code 如何识别页面元素
- 如何完成 SauceDemo 登录测试
- 如何将一次 AI 操作沉淀成可重复执行的自动化脚本
- 实践过程中遇到的问题
一、这次要完成什么任务
测试网站使用公开的自动化练习网站:
https://www.saucedemo.com/本次目标是验证下面这条业务链路:
打开登录页
→ 输入用户名和密码
→ 点击登录
→ 进入商品列表
→ 验证页面加载成功
→ 获取商品名称和价格
→ 输出测试结果测试账号:
用户名:standard_user
密码:不要在文章或截图中公开展示注意:SauceDemo 是公开演示网站,但真实项目中的账号、密码、Token 等敏感数据都应该使用环境变量保存,不能直接写进代码或提交到 GitHub。
二、我的实践环境
本次使用的主要工具:
| 工具 | 作用 |
|---|---|
| Claude Code | 理解任务、调用工具、分析结果和生成代码 |
| Playwright MCP | 为 Claude Code 提供浏览器操作能力 |
| Python | 编写可重复执行的测试代码 |
| Playwright | 浏览器自动化 |
| Pytest | 组织测试和执行断言 |
| SauceDemo | 公开 UI 自动化练习网站 |
这里需要理解一个关键关系:
Claude Code
↓ 调用
Playwright MCP
↓ 控制
真实浏览器
↓ 操作
SauceDemoClaude Code 负责理解我的自然语言测试任务,Playwright MCP 负责提供浏览器操作能力。
三、确认 Playwright MCP 已连接
在 Claude Code 中检查 MCP 状态:
claude mcp list看到类似下面的状态,说明 Playwright MCP 已经连接:
playwright - Connected但是,"连接成功"只表示 Claude Code 能找到 Playwright MCP,并不代表整个 UI 测试链路已经验证完成。
所以我继续让 Claude Code:
- 打开 SauceDemo;
- 读取页面结构;
- 识别用户名、密码和登录按钮;
- 返回识别结果。
四、我交给 Claude Code 的测试任务
我没有只输入"测试一下这个网站",而是给出了明确的测试目标、步骤、断言和输出要求。
可以参考下面这段提示词:
请使用 Playwright MCP 对 SauceDemo 执行一次真实的登录冒烟测试。
测试地址:
https://www.saucedemo.com/
测试步骤:
1. 打开登录页面。
2. 确认页面标题为 Swag Labs。
3. 识别用户名输入框、密码输入框和 Login 按钮。
4. 使用测试账号完成登录。
5. 登录成功后确认进入商品列表页面。
6. 验证页面中存在 Products 标题。
7. 获取页面中的商品名称和价格。
8. 输出每一步的执行结果。
9. 如果任何一步失败,保留截图并说明失败原因。
注意:
- 优先使用 role、label、placeholder 等稳定定位方式。
- 不要把账号密码硬编码进生成的项目文件。
- 暂时不要修改其他项目代码。这段提示词比一句"帮我做 UI 自动化"更有效,因为它明确了:
- 测试范围
- 操作步骤
- 断言条件
- 定位策略
- 失败处理
- 安全要求
五、Claude Code 如何识别页面元素
Claude Code 调用 Playwright MCP 打开页面后,读取到了登录页的可访问性结构,并识别出三个核心元素:
| 页面元素 | 识别结果 | 推荐定位方式 |
|---|---|---|
| 用户名输入框 | Username | get_by_role("textbox", name="Username") |
| 密码输入框 | Password | get_by_role("textbox", name="Password") |
| 登录按钮 | Login | get_by_role("button", name="Login") |
对应的 Playwright Python 写法类似:
page.get_by_role("textbox", name="Username").fill(username)
page.get_by_role("textbox", name="Password").fill(password)
page.get_by_role("button", name="Login").click()这里让我感受比较明显的是:AI 不只是根据网页源码猜一个 CSS 选择器,而是能够先读取页面结构,再根据元素角色和名称选择更容易维护的定位方式。
不过,AI 找到定位器并不代表定位器永远可靠。生成代码后仍然需要通过重复执行验证稳定性。
六、完成第一次真实登录测试
登录过程中,浏览器执行了下面几个动作:
进入 SauceDemo
→ 填写用户名
→ 填写密码
→ 点击 Login
→ 等待商品列表加载登录成功后,我没有只根据"页面跳转了"判断测试通过,而是增加了明确断言:
from playwright.sync_api import expect
expect(page).to_have_url("https://www.saucedemo.com/inventory.html")
expect(page.get_by_text("Products", exact=True)).to_be_visible()这样可以同时验证:
- 页面进入了正确地址;
- 商品列表的核心元素已经出现。
七、提取商品名称和价格
登录成功后,继续获取页面上的商品名称和价格:
product_items = page.locator(".inventory_item")
products = []
for index in range(product_items.count()):
item = product_items.nth(index)
products.append(
{
"name": item.locator(".inventory_item_name").inner_text(),
"price": item.locator(".inventory_item_price").inner_text(),
}
)输出的数据结构类似:
[
{
"name": "Sauce Labs Backpack",
"price": "$29.99"
},
{
"name": "Sauce Labs Bike Light",
"price": "$9.99"
}
]这里不要直接复制示例作为最终结果。文章发布前,应当使用你实际运行生成的 JSON,并确保商品数量和字段都与真实页面一致。
八、把一次操作变成可重复执行的测试
Playwright MCP 帮我操作一次浏览器,只能证明 AI 可以完成任务。
真正具有工程价值的是,把这次操作沉淀成稳定、可重复执行、能够断言和生成报告的自动化测试。
项目可以逐步整理成下面的结构:
AI-Testing-Agent/
├── framework/
│ ├── runner.py
│ └── ui_collector.py
├── projects/
│ └── saucedemo/
│ ├── config.yaml
│ └── baseline.json
├── reports/
│ ├── result.json
│ └── result.md
├── tests/
│ └── test_saucedemo_ui_flow.py
├── .env.example
├── requirements.txt
└── README.md一个基础测试示例:
import os
from playwright.sync_api import Page, expect
def test_saucedemo_login(page: Page) -> None:
username = os.environ["SAUCE_USERNAME"]
password = os.environ["SAUCE_PASSWORD"]
page.goto("https://www.saucedemo.com/")
expect(page).to_have_title("Swag Labs")
page.get_by_role("textbox", name="Username").fill(username)
page.get_by_role("textbox", name="Password").fill(password)
page.get_by_role("button", name="Login").click()
expect(page).to_have_url(
"https://www.saucedemo.com/inventory.html"
)
expect(
page.get_by_text("Products", exact=True)
).to_be_visible()在 Windows PowerShell 中,可以临时设置环境变量:
$env:SAUCE_USERNAME = "standard_user"
$env:SAUCE_PASSWORD = "你的测试密码"
pytest -v这样账号密码不会直接写入代码。
九、执行结果
运行测试:
pytest -v最终结果请写成你实际执行得到的数据,例如:
1 passed in 4.82s不要为了让文章看起来完整,提前虚构测试通过数量和执行时间。
建议文章至少展示四类证据:
- Claude Code 的真实提示词;
- Playwright MCP 操作浏览器的过程;
- 提取出的 JSON 数据;
- Pytest 执行通过结果。
十、这次实践遇到的问题
1. MCP 连接成功不等于测试跑通
最开始看到 Connected,只能说明工具配置正常。
必须真正执行页面打开、元素识别、输入、点击和断言,才算跑通完整链路。
2. AI 操作成功不等于自动化工程完成
Claude Code 可以通过 MCP 临时操作浏览器,但这种操作过程不一定能直接用于持续回归。
还需要把它沉淀成:
- 独立测试用例
- 稳定定位器
- 明确断言
- 测试数据管理
- 失败截图
- 测试报告
3. 测试目标必须描述清楚
如果只告诉 AI"帮我测试登录",它可能只完成点击操作,不一定验证登录结果。
提示词中应当明确:
操作什么
→ 如何判断成功
→ 失败后保留什么
→ 最终输出什么4. AI 生成的代码仍然需要人工审查
主要检查:
- 定位器是否稳定;
- 是否使用固定等待;
- 断言是否真正有效;
- 密码是否被硬编码;
- 异常是否被忽略;
- 测试能否重复执行。
十一、Claude Code + MCP 能替代测试工程师吗
这次实践之后,我的判断是:暂时不能简单替代,但可以明显改变 UI 自动化的工作方式。
它擅长帮助测试工程师:
- 理解自然语言测试任务;
- 探索陌生页面;
- 识别页面元素;
- 生成第一版测试代码;
- 分析执行失败原因;
- 整理测试结果。
测试工程师仍然需要负责:
- 业务风险判断;
- 测试范围设计;
- 断言是否合理;
- 数据是否准确;
- 脚本稳定性;
- 回归测试体系建设。
所以更准确的说法不是"AI 代替 Playwright",而是:
Claude Code 负责理解和协作,Playwright MCP 提供浏览器能力,测试工程师负责目标、标准与质量。
十二、下一步计划
第一次真实 UI 测试跑通后,我准备继续完成:
- 自动提取完整商品列表;
- 将页面数据保存为 JSON;
- 与基准 JSON 自动比对;
- 生成 JSON 和 Markdown 测试报告;
- 失败时自动保存截图;
- 接入 GitHub Actions 或 Jenkins;
- 逐步完善为 AI Testing Agent。
这次实践证明,从自然语言测试任务到真实浏览器操作,这条链路已经可以跑通。
但真正有价值的方向,不是让 AI 临时点击一次页面,而是把 AI 的页面理解能力与传统自动化测试工程结合起来,形成稳定、可重复、可追踪的测试流程。
我是 AI 测研社。不只谈 AI,亲自测给你看。