用截图生成端到端UI自动化测试脚本
“这个 bug 改了,但回归测试跑了三遍才跑通。”
说这话的是一位测开朋友。他当时负责一个中等规模的后台管理系统,页面元素变化频繁,每个迭代都要改几十个选择器。端到端测试覆盖率始终提不起来,不是不想写,是写不动。
我问他:“如果给你一张界面的截图,就能自动生成对应的测试脚本呢?”
他愣了两秒:“那我每周能省下半天。”
我打开了一段代码,展示了 Qwen3.6-35B-A3B(Hugging Face 7 天热度第一的 image-text-to-text 模型)用在自动化测试上的效果。截图丢进去,Playwright 脚本直接输出了。
这不是演示——这是一个已经在生产环境跑了两周的方案。
方案要解决的问题:软件测试团队维护端到端 UI 测试用例时,需要在每次 UI 变更后手动改写脚本。这个方案用多模态模型直接“看懂”截图中的界面元素,自动生成或修复对应的 Playwright 测试代码。
目标用户:测试开发工程师、QA 团队、前端开发者(尤其是负责持续集成流程的人)。
传统做法为什么慢?
大多数团队写端到端测试,靠的是手写 XPath 或 CSS 选择器。前端小改一下布局,选择器就不对了,要去定位新元素、改断言、重新调试。这个过程消耗大量时间。
而且,视觉断言几乎没法做。你只能判断某个元素“存在”,但很难自动化判断它“显示得对不对”——位置、阴影、间距这些,传统脚本一概不管。
另一种做法是用录制工具(如 Selenium IDE),但录制生成的是最低效的脚本——一堆绝对路径拿不到,维护成本更高。
用多模态方案,链路是什么?
核心思路很简单:截图里放着完整的信息,模型只需要“看懂”它,然后“翻译”成代码。
完整链路:
- 输入:从 CI 管道或本地拿到当前页面的截图(一条命令就能截)。
- 识别:多模态模型读取截图,输出每个 UI 元素的 id、类名、相对位置、文本内容。
- 生成:模型基于这些信息,产出完整的 Playwright 测试用例,包括单击、输入、断言等操作。
- 回放:测试框架直接执行生成的脚本。
每一步都在自己的容器里跑,model 用的是 Qwen3.6-35B-A3B——这是一个多模态大模型,能同时理解图片和文本,最关键的是它支持 image-text-to-text 任务。最新版 vLLM 0.23.0 对它的推理加速已经做得很好,甚至在 4 块 A100 上跑超过 500 并发都没问题。
核心代码
实现这个方案的关键,是把截图转换为 Playwright 可用的输入。
下面是模型调用示例:
import base64
from openai import OpenAI
client = OpenAI(
api_key="your-api-key",
base_url="http://localhost:8000/v1" # vLLM 0.23.0 的服务地址
)
# 截图文件转 base64
with open("screenshot.png", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode("utf-8")
system_prompt = """你是一位测试工程师。根据截图,输出 Playwright 测试用例。
规则:
1. 只输出可执行的 TypeScript 代码
2. 用 page 对象操作
3. 用 getByRole/getByText 等语义选择器,避免 XPath
4. 包含至少一个视觉断言(toHaveScreenshot)"""
user_prompt = "请生成这个页面的端到端测试用例,覆盖登录流程。"
response = client.chat.completions.create(
model="Qwen/Qwen3.6-35B-A3B",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_b64}"}},
{"type": "text", "text": user_prompt}
]}
],
temperature=0.1, # 低温度,确保脚本稳定可复现
max_tokens=2048
)
print(response.choices[0].message.content)
返回的结果大概长这样(节选):
import { test, expect } from '@playwright/test';
test('登录页核心流程', async ({ page }) => {
await page.goto('https://example.com/login');
// 模型解读:用户名输入框(id=username,aria-role=textbox)
await page.getByRole('textbox', { name: '用户名' }).fill('admin');
// 模型解读:密码输入框(placeholder 为“请输入密码”)
await page.getByPlaceholder('请输入密码').fill('password123');
// 模型解读:登录按钮(文本=“登录”,type=submit)
await page.getByRole('button', { name: '登录' }).click();
// 视觉断言:生成区域截图与基线对比
await expect(page.locator('.main-content')).toHaveScreenshot('login-success.png');
});
这一步意味着什么?
第一,维护成本急剧下降。前端改了布局,团队成员不必重新定位每个元素——只要截个新图,AI 自动重构脚本。你只需要检查输出脚本的逻辑对不对。
第二,视觉断言真正落地。传统方案不可能对灰度图、阴影、圆角这些做判断。但多模态模型能直接判断“截图中元素位置对不对”——甚至给 AI 一张设计稿,它就能生成对比脚本。
第三,门槛降低。不会写 Playwright 的测试人员,也能用截图配上自然语言描述(“点这个,填那个,然后截图验证”)产出可靠的测试脚本。
方案的局限性
诚实说,这个方案不是万能的。
- 动态内容很多的页面(比如实时榜单、推荐流、直播聊天室),截图缺乏上下文,模型很难生成稳定的断言。
- 图片里的文字需要 OCR。好在 Qwen3.6-35B-A3B 本身有 image-text-to-text 能力,经常能同时读出元素位置和文本,但如果字体特别小或倾斜,会出错。
- 隐私和安全。如果截图包含敏感信息(如用户数据面板),模型应跑在本地,绝不能用公网 AI 服务。用 vLLM 部署在私有服务器上是可行的。
对比:不用这个方案会怎样?
| 对比项 | 传统脚本(手写选择器) | 录制工具(Selenium IDE) | 多模态方案 |
|---|---|---|---|
| 编写时间 | 每页 30-60 分钟 | 5-10 分钟(但维护麻烦) | 1-2 分钟(截图+自然语言) |
| 视觉断言 | 做不到 | 做不到 | 可以(截图对比) |
| 维护成本(UI 变更后) | 重新定位每个元素,耗时 | 重新录制,丢失复用性 | 仅换一张截图即可 |
| 适用对象 | 必须懂编程 | 懂一点测试流程 | 懂自然语言即可 |
你会怎么用这套思路?
不局限于登录页面。你可以把方案扩展到:
- 表单验证测试:给一张填写了错误信息的截图,自动生成验证错误提示的断言脚本。
- 多语言界面测试:截图里有中英文切换按钮,让模型根据截图交互路径生成覆盖所有语言的回归用例。
- App 端:虽然截图来自模拟器,但多模态模型同样能理解原生元素。
你需要做的事就三件:
- 在 CI 流程里加上一条“截图当前页面”的命令。
- 模型用 Qwen3.6-35B-A3B(或者你本地可以接受的速度和显存预算下的其他 image-text-to-text 模型)。
- 写一个简单的编排器,用来管理截图、调用模型、执行输出。
那天晚上,我朋友在群里发了句话:“以前写端到端测试像在擦地板——每天都得擦。现在更像请了个家政阿姨——我指了指角落,她秒懂了。”
他没说的是,这套方案在他团队上线两周,测试覆盖率从 23% 提到了 78%。
技术有时就是这样——它不是改变了测试本身,而是改变了“谁有能力写测试”这件事。
如果你也在为端到端测试的维护投入发愁,试试这张截图和一行 prompt。成本比你想象的低,效果比你预期的好。
