Maestro 跨平台 UI 自动化测试完整实战指南:一套 YAML 流程驱动 Android、iOS 与 Web
【免费下载链接】MaestroPainless E2E Automation for Mobile and Web项目地址: https://gitcode.com/GitHub_Trending/ma/Maestro
凌晨的 CI 日志里躺着同一行红字:Element not found。页面其实已经渲染出来了,测试却死在点击那一步。这是多端 UI 测试最经典的翻车现场:三套框架各维护一套定位,再靠sleep硬赌网络。Maestro 是一个开源的跨平台 UI 自动化测试框架,一份 YAML 流程同时驱动 Android、iOS 和 Web 端,等待机制直接内置在命令里。这篇指南带你从零装好它,写出一条能在三个端都跑通的搜索用例。
一条 Element not found 暴露的三个老问题
传统做法的账单大致是三笔:
- 三套定位各写一遍:Android 用原生自动化、iOS 用另一套、Web 再搭浏览器驱动。同一句界面文案改一个字,三处脚本跟着改。
- sleep 赌加载:断言前手写等待,本地能过、CI 上挂,测试变得"时过时不过"。
- 改了才能看:写完要先编译、配环境,改一行等两分钟,迭代节奏全毁。
Maestro 的做法是把这三笔账一笔一笔抹掉:测试写成扁平的 YAML 命令列表(README 里管它叫 flow);定位不靠选择器路径,而是走系统的无障碍层——应用本来就要把"这是一个按钮,文字是搜索"这类信息暴露给读屏功能,Maestro 直接读同一份信息,所以换个端、换个框架写的 App 都能驱动;等待内置在每条命令里,找不到元素就自己等到超时为止;流程是解释执行的,改完保存直接跑。
⚡ 十分钟装好环境,跑通第一条测试
前置条件只有一个:Java 17 及以上。先跑一下确认:
java -version安装就一条命令,macOS、Linux、Windows(WSL)通用:
curl -fsSL "https://get.maestro.mobile.dev" | bash export PATH="$PATH:$HOME/.maestro/bin" maestro --version第一行拉取安装脚本,第二行把安装目录加进 PATH,第三行验证。能打印出版本号,环境就算就绪——装完是一个独立二进制,没有驱动、没有 SDK、没有依赖要伺候。
先拿仓库自带示例热身
手上还没有自己的 App?仓库里 e2e/workspaces/wikipedia/ 藏着一套现成的 Wikipedia 搜索流程,配合maestro download-samples下载的示例应用就能直接跑。等下一节学会读流程语法后,再回头跑它,你会发现每一行都认得。
写一条真实用例:搜索功能全流程
场景换到一个购物 App:打开应用,在搜索框输入"机械键盘",确认结果页里出现了目标商品。这条用例覆盖了最常用的四个命令,结构就是绝大多数流程的骨架。
逐行读懂这条 9 行流程
appId: com.example.shop tags: [smoke, search] --- - launchApp: clearState: true - tapOn: "搜索" - inputText: "机械键盘" - assertVisible: text: contains: "客制化轴体"逐行说:appId声明被测应用的包名;tags是给 CI 分流用的标签;---之后是步骤列表。launchApp加clearState: true会先清空应用数据,保证每次测试从干净状态开始;tapOn按文本点元素;inputText往焦点所在输入框填内容;assertVisible是断言——元素找不到、等待超时,这条用例就判负。
定位写不平时:contains 与正则
文本里带动态内容(订单号、时间戳)时,精确匹配必挂,改成contains只咬住稳定的一段,如上面例子。更松一档的是正则,仓库示例里就有直接写正则的断言,比如assertVisible: '.*sleek.*'这种写法,匹配"以 sleek 结尾的描述文案"。
不想硬编码数据:随机输入
注册、造数这类场景不必把测试数据写死:
- inputRandomEmail - inputRandomNumber: length: 6运行时现生成一个随机邮箱和一个 6 位数字,每次执行数据都不同。
划重点:流程里每一步都是"找元素 → 做动作 → 自动等结果"。定位写得松一点(contains、正则),界面小改版基本伤不到脚本;真正该写扎实的是断言——它决定用例结论可不可信。
断言时过时挂:把等待和重试交给框架
先说默认行为:每条tapOn、assertVisible自带等待窗口,元素晚一点出现框架会自己等,多数情况你什么都不用加。
retry:给偶发失败兜底
有些交互本身会偶发丢事件(点击没生效、页面跳得慢)。仓库里真实用例是这么兜底的(见 e2e/workspaces/simple_web_view/webview.yaml):
- retry: maxRetries: 2 commands: - tapOn: "搜索" - assertVisible: text: contains: "客制化轴体"整段"点击 + 断言"最多重试两次,全部通过才算这步完成。比无脑 sleep 强的地方在于:它是事件驱动的重试,不是时间驱动的硬等。
extendedWaitUntil:显式拉长等待上限
页面加载确实慢时,把等待上限单独调大,还能给等待起个标签方便排查日志:
- extendedWaitUntil: visible: "搜索结果" timeout: 10000 label: 等搜索结果页加载完成划重点:等待是兜底,不是药。加完
retry连跑五次仍然挂,就停手——问题多半在用例本身或前置状态,继续拉长等待只是把失败推迟到更晚。
同一份用例,怎么在 Web 端跑
移动端流程头部写appId;Web 端把头部换成url,指向页面地址,后面的步骤一个字都不用改:
url: https://shop.example.com/search --- - launchApp - tapOn: 关键词 - inputText: 机械键盘 - tapOn: 搜索 - assertVisible: 客制化轴体执行时加--platform web参数即可:
maestro --platform web test flows/web-search.yaml想看真实示例,仓库里的 e2e/workspaces/web/simple.yaml 是一条完整的 Web 登录+浏览流程。注意 Web 流程跑本地页面时,仓库用 e2e/README.md 里提到的静态服务器(e2e/ensure_fixtures脚本)来提供页面——页面没起来时launchApp也能"成功",但断言会报出指向性很差的 Element not found,这是 Web 端最容易踩的坑。
顺带一提:让 AI 代理替你点应用
CLI 内置了 MCP 服务(maestro mcp启动),Claude Code、Cursor 等支持 MCP 的编码工具可以直接操作真机或模拟器:看屏幕、点击、断言、自查结果。让它顺手把刚才的搜索用例写成 YAML,再跑一遍验证,是上手 MCP 最快的方式。
验收标准:三端跑通才算完成 ✅
到这里,验收标准只有一条:同一条搜索流程,在 Android 模拟器、iOS 模拟器(iOS 真机暂不支持)和浏览器里各跑一遍都通过,并且连续跑五次没有偶发失败。
三条命令记住就够:maestro test <流程文件>跑移动端,maestro --platform web test跑 Web 端。把通过的流程打上smoke这类标签收进 CI,以后每次提交自动回放。用例数量少没关系,三端稳定才是这条流程真正可以交接出去的时刻——到那时,你手里就不只是几条测试,而是一份三个平台共用的验收说明书。
【免费下载链接】MaestroPainless E2E Automation for Mobile and Web项目地址: https://gitcode.com/GitHub_Trending/ma/Maestro
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考