标签:Playwright | AI提效 | 自动化测试 | 豆包
1. 开场白
做 UI 自动化的同学一定深有体会:脚本失败、元素失效、超时、定位变更…… 排查一次动辄几十分钟。在快速迭代项目里,维护成本高到让人放弃。
本文分享了:Playwright + AI 视觉分析 + 自动修复,失败自动截图 → AI 分析根因 → 自动生成修复代码 → 自动重试,全流程,欢迎讨论交流!
演示效果:一键跑完40秒,AI分析2.8秒,Token约2000(不到1分钱)。
2. 演示:5分钟闭环,从报错到通过
我把一个故意写错的Playwright脚本跑一遍,pytest失败时自动截图:
测试代码(故意写错定位):
def test_saucedemo_wrong_locator(page):
page.goto("https://www.saucedemo.com")
page.fill("#user-name", "standard_user")
page.fill("#password", "secret_sauce")
page.click("text=Sign In") # ← 故意写错,实际应该是 Login
pytest执行结果:
FAILED test_demo_fail.py::test_saucedemo_wrong_locator[chromium]
playwright._impl._errors.TimeoutError: Page.click: Timeout 30000ms exceeded.
waiting for locator("text=Sign In")
=========================== 1 failed in 47.94s ============================
❌ 测试失败,已保存截图到:screenshots/test_saucedemo_wrong_locator_20260416_224543.png
截图 + 报错日志,一起发给豆包多模态模型。
发给豆包的Prompt:
你是专业Playwright自动化测试工程师。以下是一个失败的测试用例: 报错日志:
TimeoutError: waiting for locator("text=Sign In")请结合截图分析报错,给出:1.根本原因 2.修复代码
豆包回复:
根本原因:从截图中可以看到登录按钮上的文本是 "Login",而测试代码中使用了错误的文本定位 "text=Sign In",导致找不到元素,最终超时。
修复代码:将
page.click("text=Sign In")修改为page.click("text=Login")
AI秒出分析结果,精准定位根因,直接给修复代码。
把豆包给的修复代码自动写入脚本,再次运行——
$ pytest test_saucedemo.py -v
test_saucedemo.py::test_login PASSED ✅
从截图→分析→修复→重跑→通过,全程5分钟,无需人工介入。
3. 【AI自动化报错修复整体方案】架构设计
4步完整流程
第1步:执行测试 Playwright + pytest 运行测试用例
第2步:失败自动采集(Hook) 测试失败触发 conftest.py hook,自动生成3件套:
- 全页截图
- DOM结构片段(定位失败时的当前页)
- pytest执行日志
第3步:AI分析(豆包Vision) 自动调用豆包多模态模型,解析3件套,输出结构化结果:
- 判断失败类型(Flaky/业务Bug/环境问题)
- 精确定位失败点(具体选择器/等待逻辑)
- 输出可直接复制的修复代码
第4步:(可选)自动化闭环
- 提交修复代码到临时分支
- GitHub Actions自动重跑验证
【AI自动修复 · 调用时序】
- 测试用例 → pytest:执行 Playwright 自动化测试
- pytest → conftest.py Hook:测试失败,触发失败捕获钩子
- Hook → 失败文件:自动生成截图、DOM片段、执行日志
- 失败文件 → 豆包Vision:上传三套件进行多模态分析
- 豆包Vision → 自动修复脚本:返回失败类型、根因、可复制修复代码
- 自动修复脚本 → CI/GitHub_Actions:提交代码,触发自动重跑
- GitHub Actions → 测试用例:自动重跑验证,完成闭环
4. 三段核心源码(可复制!可修改!可落地!)
思路很多人都懂,怎么做才是关键。 以下是完整可落地的3段源码。
① pytest失败自动截图(conftest.py)
放在项目根目录,pytest自动加载,失败即截图:
import pytest
from playwright.sync_api import Page
from datetime import datetime
import os
SCREENSHOT_DIR = "screenshots"
os.makedirs(SCREENSHOT_DIR, exist_ok=True)
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""测试失败时自动截图"""
outcome = yield
report = outcome.get_result()
page = None
if "page" in item.fixturenames:
page = item.funcargs["page"]
if report.when == "call" and report.failed and page:
test_name = item.name
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
screenshot_path = os.path.join(SCREENSHOT_DIR, f"{test_name}_{timestamp}.png")
page.screenshot(path=screenshot_path, full_page=True)
print(f"\n❌ 测试失败,已保存截图到:{screenshot_path}")
踩坑预警:截图路径用相对路径在某些IDE下会找不到,建议用
os.path.join(SCREENSHOT_DIR, ...)拼接。
② 豆包Vision模型分析截图(doubao_vision_demo.py)
调用豆包多模态模型,截图+报错日志一起分析:
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ.get("DOUBAO_API_KEY", ""),
base_url="https://ark.cn-beijing.volces.com/api/v3"
)
def analyze_screenshot_with_text(
text_prompt: str,
image_path: str,
model: str = "doubao-1-5-vision-pro-32k-250115"
) -> str:
"""截图+文本发给豆包多模态模型,分析报错并返回修复建议"""
with open(image_path, "rb") as f:
img_data = base64.b64encode(f.read()).decode()
content = [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_data}"}},
{"type": "text", "text": text_prompt},
]
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": content}],
temperature=0.1,
max_tokens=1024
)
return response.choices[0].message.content
关键点:图片必须放在content数组的第一个位置,否则模型可能忽略图片。
③ 失败后自动分析脚本(analyze_failures.py)
测试跑完后,自动扫描截图目录,逐个发给AI分析:
import os
import glob
from doubao_vision_demo import analyze_screenshot_with_text
SCREENSHOT_DIR = "screenshots"
PROMPT_TEMPLATE = """你是专业Playwright自动化测试工程师。以下是一个失败的测试用例:
报错日志:{error_log}
请结合截图分析报错,给出:
1. 失败类型(Flaky等待/元素定位失败/业务bug/环境问题)
2. 根本原因(1-2句话)
3. 可直接复制的修复代码(Python Playwright)
4. 预防建议(1-2条)"""
def analyze_all_failures():
"""分析screenshots目录下所有失败截图"""
screenshots = sorted(glob.glob(os.path.join(SCREENSHOT_DIR, "*.png")))
if not screenshots:
print("没有失败用例!🎉")
return
for screenshot_path in screenshots:
test_name = os.path.basename(screenshot_path)
print(f"\n{'='*60}\n分析:{test_name}\n{'='*60}")
result = analyze_screenshot_with_text(
text_prompt=PROMPT_TEMPLATE.format(error_log="请从截图中判断"),
image_path=screenshot_path
)
print(result)
if __name__ == "__main__":
analyze_all_failures()
真实运行日志
=========================== 1 failed in 47.94s ============================
❌ 测试失败,已保存截图到:screenshots/test_saucedemo_wrong_locator_20260416_224543.png
============================================================
分析:test_saucedemo_wrong_locator
============================================================
### 根本原因分析
从报错日志可以看出,测试用例在等待页面上文本为 `Sign In` 的元素可点击时超时了。
结合提供的截图来看,页面上实际显示的登录按钮文本是 `Login`,而不是 `Sign In`,
这意味着测试代码中定位元素的文本选择器与页面实际内容不匹配。
### 修复代码(Python Playwright)
```python
# 将
test_saucedemo_wrong_locator(page)
page.click("text=Sign In")
# 修改为
test_saucedemo_wrong_locator(page)
page.click("text=Login")
### 全链路汇总报告(实测数据)
一键运行后,自动输出完整闭环报告:
\============================================================
🔧 Step1: 模拟运行失败的Playwright测试...
================================
📸 正在执行用例(故意让它失败),请稍候...
(这一步要等Playwright找'Sign In'找不到,最长30秒,不是卡住!)
❌ 测试失败,已保存截图到:screenshots/test\_saucedemo\_wrong\_locator\_20260417\_114558.png
⏱️ 失败用例耗时:31.82秒
\============================================================
🤖 Step2: 豆包视觉模型正在分析失败场景...
===========================
📸 正在上传截图并调用API,请稍等...
💡 豆包回复:
根本原因:按钮文本是 "Login",而代码写的是 "Sign In"
修复代码:page.click("text=Login")
⏱️ 分析耗时:2.82秒
💰 Token消耗:输入1200,输出800,总计2000
\============================================================
🔧 Step3: 自动生成修复后的v2测试脚本...
===========================
✅ 修复脚本已生成:test\_demo\_fail\_v2.py
\============================================================
✅ Step4: 自动运行v2脚本验证修复效果...
==========================
test\_demo\_fail\_v2.py . ✅ 1 passed in 2.0s
✅ v2测试用例全部通过!修复成功!
🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉
📊 全链路截图诊断修复汇总报告 📊
🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉
🔹 第一次运行(失败场景):⏱️ 31.82秒
🔹 豆包视觉分析:⏱️ 2.82秒 💰 2000 Token
🔹 自动生成v2脚本:✅ 成功
🔹 v2验证通过:✅ 1 passed in 2.0s
🔹 整体数据:
⏱️ 全链路总耗时:36.62秒
🕒 手动修复预估耗时:1800秒(30分钟)
⏳ 节省时间:1763.38秒(约29.4分钟)
🚀 效率提升:98.0%!
💡 可给领导汇报的话:
'我们用豆包视觉模型+Playwright做了自动化测试的自修复演示,
一个经典的定位器错误场景,原来手动修复要30分钟,
现在一键运行,36.62秒就搞定了,效率大幅度提升!'
从截图诊断到自动修复,全程自动化。
Token耗费
{
"model": "doubao-1-5-vision-pro-32k-250115",
"usage": {
"prompt_tokens": 1247,
"completion_tokens": 89,
"total_tokens": 1336
}
}
整个闭环只需消耗约 1336 Token,目前大模型50w免费额度,不花钱。
5. 豆包视觉模型:为什么选它?替代方案?
为什么选豆包Vision?
| 优势 | 说明 |
|---|---|
| 多模态能力强 | 同时理解截图+报错日志,定位准确率高 |
| 性价比高 | 火山引擎定价,比GPT-4V便宜一半以上 |
| 国内访问快 | 无墙,延迟低,企业内网可用 |
| Token上限够用 | 32k文本Token,完整DOM+日志都存得下 |
有替代方案吗?
| 方案 | 适合场景 | 成本 |
|---|---|---|
| 豆包-1.5-Vision-Pro-32k(推荐) | 国内企业项目 | 中等,性价比最高 |
| 豆包Lite-Vision | 新手试用、小项目 | 免费额度 |
| GPT-4V / Claude 3 | 国外项目、追求最高准确率 | 较高 |
| Qwen-VL-Max / InternVL2.5 | 有GPU资源、自建服务 | 运维成本高 |
怎么开通?
操作步骤:火山引擎控制台 → 方舟 → 创建API Key → 开通Vision模型
6. 兜底:万一AI也修不好怎么办?
加一个安全阈值兜底:
MAX_FIX_ATTEMPTS = 3
fix_attempt = 0
while fix_attempt < MAX_FIX_ATTEMPTS:
result = subprocess.run(["pytest", "-v"], ...)
if result.returncode == 0:
print("✅ 测试通过!")
break
# 截图发给AI
ai_response = analyze_screenshot_with_text(...)
fix_code = extract_fix_code(ai_response)
# 应用修复
apply_fix(fix_code)
fix_attempt += 1
else:
# AI尝试3次仍未修好,人工介入
raise RuntimeError(
f"⚠️ AI尝试{MAX_FIX_ATTEMPTS}次修复未通过。"
"可能是复杂Bug,需人工介入定位。"
)
3次兜底逻辑:普通定位错误通常1次修好;复杂场景3次修不好,说明需要人工介入,避免AI无意义循环。
7. 这套方案怎么用到我的项目?
最小改动原则(改这5个地方就能用!)
| 改动点 | 具体操作 | 难易度 |
|---|---|---|
| 替换被测URL | 环境变量里改 BASE_URL | ⭐ 简单 |
| 替换fixture名称 | 如果你的fixture叫 browser_page,在 conftest.py 里改 | ⭐ 简单 |
| 替换API Key | export DOUBAO_API_KEY=你的火山引擎Key | ⭐ 简单 |
| 调整提示词模板 | 根据业务规范修改分析维度 | ⭐⭐ 中等 |
| 调整Token限制 | DOM/日志超过50KB时,适当压缩 | ⭐⭐ 中等 |
通用化扩展思路
- 多项目复用:每个项目单独建
conftest.py+config.py,共享doubao_vision_demo.py - 多模型切换:换模型名+换prompt即可,一键切换豆包/DeepSeek/GPT
- CI/CD集成:把
analyze_failures.py放到GitHub Actions/Jenkins流水线,失败自动发分析结果到企业微信/钉钉群 - 自动提交修复:用GitPython库,把AI生成的修复代码提交到临时分支,并发PR
8. 进阶预告:恭候高手共建
这套方案可以做成一个可扩展的测试Skill,支持:
- ✅ 自定义AI模型(豆包/DeepSeek/GPT/开源模型)
- ✅ 自定义报错处理逻辑(特定Flaky超时直接重试,不用AI分析)
- ✅ 自定义报告格式(Markdown/HTML/Excel/企业微信卡片)
- ✅ 自动Jira bug创建、测试文档生成等插件扩展
恭候各位高手来 星球 「欢乐马自动化测试实战」一起讨论共建!
9. 适用场景
| 场景 | AI修复价值 |
|---|---|
| 定位失效(超时/找不到元素) | 看图判断,秒出正确定位 |
| UI改版导致用例失败 | AI识别变化点,自动更新定位 |
| 回归测试批量失败排查 | 截图+AI批量分析,省时省力 |
| 学习阶段调试脚本 | 新手用AI辅助定位,少走弯路 |
不管是文本定位错、ID被改、弹窗遮挡——这套方案都能用。
10. 源码包
完整可运行的源码包分两个版本:
🟢 入门版(适合演示/领导/新手)
- ✅
conftest.py— pytest失败自动截图钩子 - ✅
doubao_vision_demo.py— 豆包Vision API调用封装 - ✅
screenshot_feedback_demo_v2.py— 一键闭环主脚本 - ✅
analyze_failures.py— 批量分析失败截图脚本 - ✅
screenshots/— 失败截图示例 - ✅
README.md+Q&A.md— 4步跑通说明
👉 想给领导演示"AI自动修复测试"?不用录视频,一键运行就够了。 改URL和Key就能用,全程36秒,Token不到1分钱。
🟡 高级版
6模块,3用例(登录/浏览/结账),POM设计模式 + MCP多Agent并发执行,适合接入CI/CD流水线。
本文源码包配套:pytest截图Hook + 豆包Vision API调用 + 批量分析脚本,改URL和Key就能用到你的项目