拆字节开源的 Midscene.js:GUI Agent 做 UI 测试,为什么可以不写选择器

举报
霍格沃兹测试学社 发表于 2026/09/11 15:58:02 2026/09/11
【摘要】 字节开源的Midscene.js是跨端GUI Agent测试框架,以视觉理解替代传统选择器,AndroidWorld基准Pass@1达93.10%。它用自然语言描述操作意图,自动定位图标、Canvas等难选元素,大幅降低UI重构维护成本,但需权衡模型调用开销与判定不确定性。

在 AndroidWorld 这个移动端 GUI Agent 基准上,字节开源的 Midscene.js 官方公布的成绩是 Pass@1 93.10%(配置 Midscene 1.9.5 + Gemini-3.5-Flash)。更反直觉的是它做 UI 测试的方式:整套登录、搜索、下单流程,你可以一个选择器都不写。

传统 UI 自动化最大的维护成本,从来不是写用例,而是选择器——前端把 class 改个名、把表单换成组件库、把 data-testid 挪个位置,一整套回归脚本当天全红,哪怕页面在用户眼里一模一样。Midscene.js 这类 GUI Agent 的思路,是用自然语言描述意图、让视觉模型看着截图找元素,从根上绕开选择器这条脆弱链路。

这篇把它拆开:怎么定位、怎么断言、稳定性代价在哪、什么场景该用什么场景别用。

一、93.10% 这个数字,先说清楚它是什么

先把数据摆正,免得被单一数字带节奏。以下是 Midscene.js 官方文档站公布的基准成绩:

基准 成绩 测试配置(官方标注)
AndroidWorld Pass@1 93.10%、Pass@2 95.69%、Pass@3 97.41% Midscene 1.9.5 + Gemini-3.5-Flash
MobileWorld Pass@1 78.63%(92/117) Midscene 1.10.3 + Gemini-3.6-Flash
AppControlBench Pass@1 96.7%(58/60) Midscene 1.12.0 + Doubao Seed 2.1 Turbo

10-配图1.png

两个读数要点。第一,Pass@1 / @2 / @3 是递增的(93.10% → 95.69% → 97.41%),这本身就在说明:单次执行存在不稳定性,多给几次尝试通过率会往上走。这是视觉模型路线的固有特征,后面第五节会展开。第二,成绩强绑定模型和版本,换一个模型、换一个 Midscene 版本,数字就不一样,别把 93.10% 当成一个脱离配置的绝对值。

需要强调的是,这些是官方在标准基准上的自报成绩,反映的是「GUI Agent 这条路线已经能打到什么水平」,不等于你项目里的通过率。

二、它到底是什么:一个跨端的视觉 GUI Agent

Midscene.js 官方定位是「开源 GUI Agent + Testing Kit」,用一套 Agent API 覆盖 Web、Android、iOS、HarmonyOS 和桌面应用,MIT 协议,GitHub 在 web-infra-dev/midscene。它的核心工作方式,官方描述得很直白:像人用软件一样——观察屏幕、根据看到的内容操作、再检查界面呈现的结果。

你用自然语言描述任务和预期,它根据截图判断在哪里操作、界面是否符合预期。官方特别点出它能定位选择器最难搞的那几类元素:纯图标按钮、自定义控件、<canvas> 里的内容、跨域 iframe 里的元素——这些恰恰是传统选择器要么写不出、要么写得极其脆弱的地方。

除了 Agent API,它还配了一套 Testing Kit,把「零散的视觉操作」组织成可持续维护的 E2E 工程:既能在 Playground(Chrome 插件)里交互式试指令,也能用 YAML 直接写 UI 流程和预期结果;Beta 阶段的 Midscene Test(@midscene/test)更进一步,把声明式测试意图和可编程实现分离——YAML 描述流程,可复用的 TypeScript 节点封装 API 调用、数据准备和清理,一条退款用例可以先用 API 造订单、再用 UI 申请退款并验证结果。跑完之后,它会生成交互式 HTML 报告,把每一步的截图、元素定位、AI 决策过程、操作与断言结果全都记录下来。这份报告是它相对传统自动化的一个隐性优势:失败时你能看到模型当时「看到了什么、为什么这么判断」,而不是只有一句 element not found

三、它怎么定位:视觉理解,而不是选择器

10-配图2.png

这是整条技术路线的分水岭,值得单独拎出来对比:

维度 传统选择器(Playwright/Selenium) Midscene 视觉定位
定位依据 DOM 结构、id/class/data-testid/属性 元素的外观和位置(截图 + 多模态模型理解)
DOM 重构时 选择器失效,脚本成片报错 只要视觉语义不变,仍能命中
可读性 #login-form input[name=u],需懂前端结构 用户名输入框,业务同学也能读懂
确定性 高,命中即唯一 依赖模型判断,存在假阳/假阴
canvas/图标按钮/跨域 iframe 常常无从下手 官方明确支持
调试成本 定位失败信息精确到节点 需看 HTML 报告里的截图和 AI 决策过程

一句话概括这个取舍:传统选择器用「确定性」换来了「脆弱」,视觉定位用「脆弱性的降低」换来了「确定性的下降」。 它不是免费的升级,而是一次权衡的转移。

四、怎么断言,以及官方自己给的确定性补丁

Midscene 的断言也是视觉式的:aiAssert('登录成功后右上角显示了用户头像'),它像人工测试一样观察截图判断预期是否呈现。

但这里有个非常关键、且来自官方一手的细节——Midscene 官方文档明确写了:断言在测试脚本里至关重要,为降低模型假阳/假阴的风险,需要确定性校验时,应把 aiQuery 和标准 JavaScript 断言组合使用。 官方给的原话示例是:与其 aiAssert('商品价格是 7.99'),不如先 aiQuery 把商品名和价格取成结构化数据,再用 expect(item.price).toBe(7.99) 做判定。

这条官方建议本身就说明:纯视觉断言不适合承载「必须精确、必须可复现」的判定。 正确的用法是分两层——用视觉能力去定位和操作(发挥它抗变更的长处),用 aiQuery 取数据 + 标准断言去做确定性判定(补回它不确定的短板)。

五、稳定性代价:把账算清楚

任何「绕开选择器」的方案,代价都转移到了别处。Midscene 的代价清单如下:

代价维度 具体表现 缓解手段(官方能力)
判定非确定性 同一脚本两次跑,视觉定位/断言结果可能不同(Pass@1<@2<@3 即证据) 关键断言改用 aiQuery + JS expect
模型成本 每步操作/断言都调多模态模型 官方称 AppControlBench 60 任务总费用 0.59 美元;纯截图不发庞大 DOM
执行延迟 视觉理解比读 DOM 慢 缓存 AI Planning 与定位结果,官方示例 51s→28s
数据隐私 截图直接发给你选的模型 provider 可换可自托管的开源模型(Qwen3.x、UI-TARS 等)
环境依赖 结果强绑定模型与版本 锁定模型/版本,把配置写进 CI

10-配图3.png

这里要澄清一个高频混淆:这条路线和「视觉回归」不是一回事。 视觉回归比的是两次截图的像素差异,回答「页面有没有变样」;GUI Agent 理解界面语义并执行操作,回答「这条业务流程能不能走通、结果对不对」。前者是守成的比对,后者是驱动的测试。别把 Midscene 当成截图 diff 工具来用。

六、代码对照:同一条登录流程,两种写法

来看真实 API 写的可跑用例。场景:用正确账号密码登录,验证进入用户中心。

Midscene 写法(视觉 Agent,全程零选择器):

// login.midscene.spec.ts
import { test, expect } from '@playwright/test';
import { PlaywrightAgent } from '@midscene/web/playwright';

test('用户能用正确账号密码登录', async ({ page }) => {
  await page.goto('https://shop.example.com/login');
  const agent = new PlaywrightAgent(page);

  // 用自然语言描述意图,视觉模型自己找到输入框和按钮
  await agent.aiInput('用户名输入框', { value: 'test_user' });
  await agent.aiInput('密码输入框',   { value: 'P@ssw0rd' });
  await agent.aiTap('登录按钮');

  // 等待跳转后的界面出现
  await agent.aiWaitFor('页面已进入用户中心并显示了欢迎语', { timeoutMs: 8000 });

  // 视觉断言:判断用户真正看到的结果
  await agent.aiAssert('右上角显示了用户头像,且没有出现登录失败的红色提示');

  // 需要确定性判定时,按官方建议用 aiQuery 取数据 + 标准断言
  const info = await agent.aiQuery<{ name: string; loggedIn: boolean }>(
    '{name: string, loggedIn: boolean}, 返回当前登录用户名和登录状态',
  );
  expect(info.loggedIn).toBe(true);
  expect(info.name).toBe('test_user');
});

传统 Playwright 写法(每一步都绑定选择器):

// login.playwright.spec.ts
import { test, expect } from '@playwright/test';

test('用户能用正确账号密码登录', async ({ page }) => {
  await page.goto('https://shop.example.com/login');

  // 前端一旦改结构/改 class/换组件库/挪 data-testid,下面几行当天全崩
  await page.locator('#login-form input[name="username"]').fill('test_user');
  await page.locator('#login-form input[type="password"]').fill('P@ssw0rd');
  await page.locator('#login-form button.submit-btn').click();

  await page.waitForSelector('.user-center .welcome-text', { timeout: 8000 });

  await expect(page.locator('.user-center .avatar')).toBeVisible();
  await expect(page.locator('.login-error')).toHaveCount(0);

  const name = await page.locator('.user-center .username').innerText();
  expect(name).toBe('test_user');
});

两段脚本功能等价,但维护成本的来源完全不同。传统写法里有 6 个选择器耦合点,每一个都是一次「前端改结构就断」的风险;Midscene 写法里,定位靠的是「用户名输入框」「登录按钮」这种视觉语义,只要界面看起来还是那个样子,DOM 怎么重构它都还能命中。

代价也写在里面了:Midscene 那几行 aiInput/aiTap/aiAssert 每一步都要调模型,慢、有成本、且不是 100% 可复现——所以最后一段确定性判定,我按官方建议用了 aiQuery + expect,而不是全靠 aiAssert。这就是这条路线的正确姿势。

七、什么场景该用,什么场景别用

场景 建议 理由
前端频繁重构、选择器天天失效 推荐 视觉定位对 DOM 变更不敏感,维护成本骤降
纯图标按钮、自定义控件、canvas、跨域 iframe 推荐 选择器难写或写不了,正是它的强项
Web/Android/iOS/HarmonyOS/桌面 跨端复用 推荐 一套意图描述跨平台,端上重写成本低
探索性测试、冒烟测试、快速验证关键路径 推荐 自然语言上手快,YAML/Playground 即可试
金额、状态等必须精确可复现的判定 谨慎 纯 aiAssert 有假阳/假阴,须配 aiQuery+JS 断言
超大回归套件、CI 时长/成本极敏感 谨慎 每步调模型,成本与延迟会随用例数放大
截图绝不能出内网、又无自托管模型 别用 数据隐私红线;除非自托管 Qwen3.x/UI-TARS

八、写在最后

Midscene.js 这类 GUI Agent 真正的价值,不是「让 AI 替你点按钮」,而是把 UI 自动化里最脏最累的那部分——选择器的长期维护——从根上拿掉了。

但它没有消灭成本,只是把成本从「前端一改就修脚本」转移到了「模型调用的钱、时间,和判定的不确定性」上。

想清楚这笔账的人,会把它用在界面善变、跨端、探索性的场景,同时在关键判定上老老实实退回 aiQuery + expect 的确定性写法。工具替你绕开了选择器,但没替你绕开工程判断。

我们在持续拆各类开源测试工具的技术路线与真实代价,如果你在评估要不要把 GUI Agent 引进你的 UI 自动化,留言区聊聊你的场景,我帮你对一下该用哪部分、别用哪部分。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。