很多团队的测试用例平台里,已经沉淀了大量“人能看懂”的描述性用例:进入订单页、筛选待支付订单、点击详情、校验金额。问题是,这些用例不能直接跑。QA 仍然要逐条理解业务逻辑、补元素定位、写脚本、调路径。到一个中等规模模块,转化成本很容易变成数人天。
AI UITester 这类 AI Native UI 自动化测试思路,核心价值不是“让 AI 点页面”这么简单,而是把测试资产从自然语言用例,推进到可执行、可回放、可维护的自动化流程。
痛点不在写脚本,而在翻译业务意图
传统 UI 自动化最耗时的部分,通常不是 click() 或 expect() 这几行代码,而是用例平台到测试脚本之间的翻译:
- 描述性步骤里包含业务语义,但缺少稳定的页面定位信息。
- 同一句“提交订单”,在不同页面可能对应不同按钮、弹窗和前置条件。
- 用例描述往往省略了等待、断言、异常分支和登录态准备。
- QA 写完脚本后,还要反复调试页面加载、元素遮挡、异步接口等问题。
AI UITester 的新范式,是让 AI 参与这段“理解并执行”的链路。它读取描述性用例,结合页面结构、可访问性信息、DOM、截图或运行反馈,生成并修正可执行步骤。这样,QA 的工作重心从“逐行翻译脚本”转向“审核意图、补充规则、维护关键路径”。
AI Native UI 测试应该长什么样
一个更实用的 AI UITester 流程,可以拆成四个环节:
- 用例理解:从测试平台读取自然语言步骤,识别目标页面、动作、输入数据和断言。
- 页面观察:获取 DOM、ARIA role、文本、截图或当前 URL,判断哪个控件最符合动作意图。
- 动作执行:把意图转换成 Playwright、Selenium、Appium 等测试框架能执行的命令。
- 反馈修正:执行失败时,把错误、页面状态和历史动作交给模型,让它尝试换定位、补等待或报告不可自动化原因。
这里的关键边界是:AI 不应该绕开测试框架。它应该产出或驱动可审计的自动化步骤,而不是把测试过程变成一个黑盒。否则,一旦测试误判,团队很难追踪到底是业务变了、页面变了,还是模型选错了按钮。
可以这样实践:用描述性用例生成 Playwright 脚本
下面是一个最小伪项目示例,用来演示“描述性用例 → 可执行 UI 测试”的落地方式。示例假设你使用 Playwright,并用一个 LLM API 把自然语言步骤转成测试代码。你需要把 LLM_API_KEY 和 LLM_API_URL 换成自己环境里的配置。
创建项目:
mkdir ai-uitester-demo
cd ai-uitester-demo
npm init -y
npm i -D @playwright/test
npx playwright install chromium
准备一个描述性用例文件 case.json:
{
"case_id": "order-001",
"title": "筛选待支付订单并查看详情",
"base_url": "https://example.com",
"steps": [
"打开订单列表页",
"筛选状态为待支付的订单",
"点击第一条订单的详情按钮",
"校验详情页展示订单金额"
]
}
生成脚本的 Node.js 示例 generate-test.mjs:
import fs from "node:fs/promises";
const testCase = JSON.parse(await fs.readFile("case.json", "utf8"));
const prompt = `
你是一个资深 QA 自动化工程师。
请把下面的描述性 UI 测试用例转换成 Playwright 测试代码。
要求:
- 使用 @playwright/test。
- 优先使用 getByRole、getByLabel、getByText 等语义定位。
- 不要使用脆弱的绝对 XPath。
- 对关键业务结果添加 expect 断言。
- 只输出 JavaScript 代码,不要解释。
用例:
${JSON.stringify(testCase, null, 2)}
`;
const response = await fetch(process.env.LLM_API_URL, {
method: "POST",
headers: {
"content-type": "application/json",
"authorization": `Bearer ${process.env.LLM_API_KEY}`
},
body: JSON.stringify({
model: "your-ui-test-model",
messages: [{ role: "user", content: prompt }]
})
});
if (!response.ok) {
throw new Error(`LLM request failed: ${response.status} ${await response.text()}`);
}
const data = await response.json();
const code = data.choices?.[0]?.message?.content ?? "";
await fs.mkdir("tests", { recursive: true });
await fs.writeFile("tests/order.spec.js", code);
console.log("Generated tests/order.spec.js");
运行生成与测试:
export LLM_API_URL="https://your-llm-provider.example/v1/chat/completions"
export LLM_API_KEY="replace-with-your-key"
node generate-test.mjs
npx playwright test --headed
这个例子不是说 AI UITester 必须长成这样,而是说明一个可控的工程方向:AI 负责把描述性意图转成初始脚本,Playwright 负责真实执行,QA 负责审核生成结果和补充业务规则。
让 AI 生成脚本之前,先约束输出
如果直接把“帮我写 UI 自动化”丢给模型,结果通常不稳定。更可靠的做法是给它明确边界:
- 定位策略优先级:role、label、text、test id,再考虑 CSS。
- 禁止使用绝对 XPath、随机 class、深层 DOM 路径。
- 每个用例必须包含业务断言,而不是只验证页面没有报错。
- 失败时输出原因分类:定位失败、等待超时、业务数据缺失、环境异常。
- 生成脚本要进入代码评审,而不是直接合入主干。
也建议前端团队配合补充稳定的测试钩子。例如:
<button data-testid="order-filter-status">订单状态</button>
<button data-testid="order-detail-button">查看详情</button>
<span data-testid="order-amount">¥128.00</span>
对应的 Playwright 断言可以更稳定:
import { test, expect } from "@playwright/test";
test("筛选待支付订单并查看详情", async ({ page }) => {
await page.goto("https://example.com/orders");
await page.getByTestId("order-filter-status").click();
await page.getByRole("option", { name: "待支付" }).click();
await page.getByTestId("order-detail-button").first().click();
await expect(page.getByTestId("order-amount")).toContainText("¥");
});
AI 可以减少翻译成本,但稳定测试仍然依赖页面可测试性。没有稳定语义、没有清晰断言、没有可控数据,AI 只会更快地产生一批脆弱脚本。
落地时的检查清单
引入 AI UITester,可以从一个中等复杂度模块开始,而不是一次性覆盖所有回归场景。
建议优先选择:业务流程清晰、页面结构稳定、已有描述性用例质量较高、失败成本可控的模块。不要一上来就挑战大量动态表格、复杂拖拽、强依赖第三方系统的场景。
上线前检查这些点:
- 描述性用例是否包含明确输入、操作和预期结果。
- 页面是否有稳定的 role、label、text 或 test id。
- 生成脚本是否可读、可审、可回放。
- 执行失败后是否保留截图、trace、日志和模型输入输出。
- QA 是否拥有最终确认权,而不是把质量判断完全交给模型。
AI UITester 的价值,不是替代 QA,也不是让自动化测试变得“零成本”。它更像一层新的编译器:把人类语言里的测试意图,编译成机器可以执行的 UI 行为。只要边界设计清楚,它能把数人天的用例转化工作压缩到更短的审核和修正周期里。