框架全解系列 · 第 7 篇(前 6 篇:Selenium / Playwright / Cypress / Espresso / Appium / XCUITest)
事实版本:Maestro CLI 2.10.0(2026-08-31 发布)|开源、Kotlin、15.7k+ stars|本地核心能力免费

开篇:先把 Maestro 在系列里的位置摆正

#框架运行位置测试形态一句话标签
01Selenium浏览器进程外(HTTP 协议)命令式多语言Web 自动化鼻祖、WebDriver 协议、跨浏览器
02Playwright浏览器进程外(CDP/协议直连)声明式多语言多浏览器上下文、自动等待、网络拦截
03Cypress浏览器进程内声明式 JS浏览器内自动等待的前端测试
04EspressoApp 同进程命令式 Java/KotlinAndroid 白盒、与 UI 线程强同步
05Appium进程外(黑盒)命令式多语言统一协议、双端一套脚本、驱动插件化
06XCUITest独立进程、白盒命令式 SwiftiOS 官方、自动同步、原生稳定性
07Maestro进程外(黑盒)声明式 YAML不写代码、自动等待重试、一套 YAML 跑三端

读这篇之前,先记住三个"混血"事实,它们是全文的主线:

  1. 位置和 Appium 同侧:Maestro 从设备外部"驾驶"UI,不侵入 App 进程、不要求加测试依赖、不编译测试 APK——这点和 Espresso / XCUITest 完全相反。
  2. 写法和 Cypress 神似:你只描述"我要做什么结果"(点"登录"、看见"欢迎"),不描述"怎么等、怎么重试"。等待、轮询、容错由框架默认接管。
  3. 载体是 YAML 而不是代码:没有编译器、没有测试框架脚手架,解释执行、改完即跑,手工测试、产品、开发都能写。

一句话本质

维度说明
是什么一个单二进制 CLI(+ 可选的 Studio / Cloud),把人类可读的声明式 YAML,翻译成设备级的真实输入事件
不是什么不是又一个 WebDriver 实现,不暴露 DesiredCapabilities,也不需要常驻的 Server 进程和驱动安装
核心赌注“移动端 UI 天生不稳定,与其要求测试者手写一堆等待和重试,不如让框架把这件事做掉”

01 Maestro 完整工作原理(结合架构图)

一句话本质:CLI 解释 YAML,通过设备无障碍/输入系统从外部"按下真实拇指"

┌──────────────────────────── Maestro CLI(单个 JVM 二进制)────────────────────────────┐
│                                                                                        │
│   Flow 解释器        执行编排引擎 Orchestrator        自动同步 Scheduler                │
│  ┌──────────┐      ┌──────────────────────┐      ┌──────────────────────────┐         │
│  │ YAML 解析│ ───▶ │ 命令 → 设备动作映射   │ ───▶ │ 每步前:等 UI 空闲/元素   │         │
│  │ 变量/条件│      │ runFlow/JS/tags 调度  │      │ 出现 settle,失败自动重试 │         │
│  └──────────┘      └──────────┬───────────┘      └─────────────┬────────────┘         │
│                              │                                 │                       │
│                     ┌────────▼─────────┐              ┌────────▼─────────┐            │
│                     │  语义选择器解析   │              │  视图树轮询/截图  │            │
│                     │ text/id/关系定位 │              │ (hierarchy dump) │            │
│                     └────────┬─────────┘              └────────┬─────────┘            │
└──────────────────────────────┼────────────────────────────────┼──────────────────────┘
                               │ 注入真实输入事件                │ 反复抓取视图树
              ┌────────────────┴───────────────┐
              ▼ Android                          ▼ iOS
   ┌────────────────────┐            ┌──────────────────────────┐
   │ adb / input 事件注入 │            │ idb / simctl 驱动模拟器   │
   │ UiAutomator 无障碍   │            │(底层复用 XCUITest 能力) │
   │ 真机 + 模拟器均支持   │            │ 本地:模拟器;真机走 Cloud │
   └────────────────────┘            └──────────────────────────┘
              ▼ Web
   ┌────────────────────────────┐
   │ 内置 Chromium / 连接浏览器 │
   └────────────────────────────┘

图注:上图从左到右是"YAML 进、设备动作出"的数据流;下方按 Android / iOS / Web 三个驱动分叉。编号 ①~⑧ 的运行时序见下表。

Maestro 在移动测试体系里的位置

对比项白盒派(Espresso / XCUITest)Maestro(黑盒派)
是否进入 App 进程进入(同进程 / 独立测试进程但注入)不进入,从设备外部操作系统 UI
是否需要源码/测试依赖需要编译 test APK、加依赖零插桩,App 装着就能测
能操作系统设置/别的 App受限(要授权、跨 App 困难),它驾驶的是整台设备
与技术栈耦合Kotlin/Java 或 Swift 强耦合框架无关,Compose/Flutter/RN/原生通吃
速度极快(进程内直连)略慢(每次都要 dump 视图树 + 注入)

关键设计取向:Maestro 主动拥抱"移动 UI 不稳定"这个前提。官方文档原话是"Maestro embraces the instability of mobile applications and devices and tries to counter it"(拥抱不稳定性并设法抵消)。这与白盒派"我和 App 同步、所以我快且稳"的思路是两条哲学。

一次点击的完整时序(图中编号 ①~⑧)

- tapOn: "Login" 为例,从 CLI 启动到点击落地:

步骤阶段发生了什么
读取 Flowmaestro test login.yaml 启动,Flow 解释器解析 YAML、注入 env 变量、展开 runFlow 子流程
选择设备自动发现已连接设备:Android 走 adb devices,iOS 走模拟器列表;多个设备时可用 --device 指定
建立驱动Android 建立 adb 通道;iOS 通过 idb/simctl 连接模拟器;不需要装任何驱动包到设备
dump 视图树执行器抓取当前屏幕的完整层级(含文本、accessibility label、id、坐标、可见性)
语义匹配选择器解析器在视图树里找"Login":先匹配可见文字,再匹配无障碍标签 / id
自动等待若没找到 → 不立即失败,按超时(默认约几秒)反复 dump + 等待 UI settle(等动画、渲染、网络回落)
注入事件命中后,计算元素中心坐标,通过设备输入管道(Android input tap / iOS 对应事件)注入系统级点击,如同真拇指
重试/确认点击后若下一条断言仍不满足,按内置稳定性策略重试该动作,再进入下一条命令

④→⑥ 的"抓树—匹配—等待—再抓树"循环,就是 Maestro 自动等待和抗 flaky 的物理实现;它替代了 Appium 里你手写的 WebDriverWait 和满屏的 sleep

Android / iOS 底层各靠什么驱动

平台底层通道本地支持真机说明
AndroidADB + 系统 input / UiAutomator 无障碍能力✅ 真机 + 模拟器通过 Android 显示与输入栈操作,与 App 用什么框架无关
iOSidb / simctl 驱动模拟器,底层复用 Apple XCUITest 能力⚠️ 本地仅模拟器物理 iPhone 本地不支持,真机测试需走 Maestro Cloud
Web内置 Chromium / 连接浏览器桌面 + 移动浏览器同一套 YAML,配置区把 appId 换成 url

Maestro 和 Appium 到底差在哪(同为黑盒,最容易被问)

维度AppiumMaestro
架构形态常驻 Server(:4723)+ 平台驱动插件 + 多语言 Client单 CLI,无 Server、无驱动安装
测试载体命令式代码(Java/Python/JS…)声明式 YAML(边角才用 JS)
等待显式等待,自己写自己维护自动等待,默认接管
flaky 处理自己写重试/稳定性逻辑内置重试 + 稳定性启发式
谁能写工程/SDET手工测试、QA、PM、开发都能写
平台广度通过驱动覆盖 Android/iOS/Web/Win/macOS/TVAndroid/iOS/Web
扩展方式任意语言,代价是配套脚手架YAML 优先,JS 补边缘

一句话:Appium 给你最大自由度,代价是把"等待和稳定"的责任留给你;Maestro 收走自由度,把"等待和稳定"变成默认值。


02 核心语法与定位策略

Flow 文件解剖:两段式,用 --- 分隔

# ===== 配置区(--- 之上)=====
appId: com.example.app          # 必填:被测 App 的包名/BundleId
name: 登录冒烟用例               # 可选:Flow 名称
tags:                           # 可选:标签,用于筛选运行
  - smoke
  - login
env:                            # 可选:环境变量
  USERNAME: "test@example.com"
  PASSWORD: "Test@1234"
---
# ===== 命令区(--- 之下)=====
- launchApp
- tapOn: "用户名"
- inputText: ${USERNAME}
- tapOn: "密码"
- inputText: ${PASSWORD}
- tapOn: "登录"
- assertVisible: "欢迎回来"
区块位置作用
配置区--- 之上声明 appId(或 Web 的 url)、name、tags、env、常量
命令区--- 之下一串按顺序执行的声明式命令

语义选择器:tapOn 的匹配优先级

Maestro 不鼓励坐标和 XPath,优先用语义信息(这也是它抗布局变化的关键):

匹配方式写法说明
可见文字- tapOn: "Login"匹配屏幕上显示的文本
无障碍标签同上文字命不中时匹配 accessibility label / contentDescription
id- tapOn: { id: "btn_login" }取 view 的 resource-id / accessibility identifier
点坐标- tapOn: { point: "50%,80%" }百分比或绝对坐标,最后手段
关系定位- tapOn: { text: "标题", below: "搜索框" }above/below/leftOf/rightOf 限定相对位置
子元素childOf: ...在某个容器内找
- tapOn:
    text: "立即购买"
    below: "商品详情"
    retryTapIfNoChange: true

设计意图:tapOn: "Email" 命中的是"文字或无障碍标签",因此一次改版只要按钮意思没变,脚本就不会挂;而坐标/XPath 在布局微调时立刻失效。

断言与自动等待

命令作用是否自动等待
assertVisible: "Welcome"断言某元素可见✅ 等它出现
assertNotVisible: "Loading"断言某元素消失✅ 等它消失
assertTrue: ...配合 JS 表达式做复杂断言
- assertVisible: "订单提交成功"
- assertNotVisible: "加载中"

常用命令速查表

类别命令典型用途
App 生命周期launchApp / clearState / stopApp / clearKeychain启动、清数据给"刚安装"状态
交互tapOn / doubleTapOn / longPressOn / swipe / scroll点击、长按、滑动
输入inputText / eraseText / hideKeyboard填表单、收起键盘
断言assertVisible / assertNotVisible / assertTrue校验结果
列表scrollUntilVisible滚到目标元素出现
系统toggleAirplaneMode / toggleWifi / pressKey系统级操作
流程runFlow / runScript / evalScript子流程复用、JS 兜底
条件runFlow: { when: { visible: ... }, commands: [...] }按屏幕状态分支
调试screenshot / copyTextFromClipboard / extendTimeout截图、取剪贴板
网络openLink拉起深链/URL

条件、循环、子流程、参数

# 条件分支:权限弹窗出现才点
- runFlow:
    when:
      visible: "允许"
    commands:
      - tapOn: "允许"

# 循环输入多组数据(配合 env/参数)
- runFlow:
    when:
      platform: Android
    commands:
      - tapOn: "仅在安卓点的元素"

子流程复用(runFlow 引用文件):

- runFlow: login.yaml
- runFlow:
    file: add_to_cart.yaml
    env:
      PRODUCT: "矿泉水"

命令行注入参数(双端不同 appId 的常用做法):

maestro test -e APP_ID=com.example.android flow.yaml
maestro test --env APP_ID=com.example.ios flow.yaml
appId: ${APP_ID}
---
- launchApp

JS 兜底:YAML 不够用时的逃生口

手段用途
evalScript执行 JS 表达式,把结果存进变量
runScript跑一个 .js 文件,处理复杂逻辑
- evalScript: { script: "output.dynamicText = '总价 ' + (2 * 3) + ' 元'" }
- assertVisible: "${output.dynamicText}"

经验:90% 的移动端场景 YAML 足够;只有复杂计算、动态字符串、特殊数据构造才请 JS 出场。这和 Appium"一切皆代码"形成鲜明对比。


03 完整实战:YAML 走通"登录 → 浏览商品 → 加购 → 下单断言"

Step 1:工程准备(一次性)

要求
设备Android 模拟器/真机打开 USB 调试,或 iOS 模拟器启动
安装App 已安装到设备(Maestro 默认不帮你装,可用 CI 先 adb install
目录建议 flows/ 下按功能拆文件:login.yamlcheckout.yamlsmoke.yaml

Step 2:主流程 + 可复用子流程

flows/login.yaml(登录子流程,带参数):

appId: ${APP_ID}
---
- tapOn: "用户名"
- inputText: ${USER}
- tapOn: "密码"
- inputText: ${PASS}
- tapOn: "登录"
- assertVisible: "首页"

flows/smoke_order.yaml(主流程:组合 + 业务动作):

appId: ${APP_ID}
name: 下单冒烟全链路
tags:
  - smoke
env:
  USER: "test@example.com"
  PASS: "Test@1234"
---
- launchApp:
    clearState: true            # 干净起步,避免缓存导致 flaky

- runFlow:                       # 复用登录
    file: login.yaml
    env:
      APP_ID: ${APP_ID}
      USER: ${USER}
      PASS: ${PASS}

- tapOn: "搜索"
- inputText: "矿泉水"
- pressKey: Enter
- scrollUntilVisible:            # 滚到目标商品
    element: "天然矿泉水 550ml"
    direction: DOWN
- tapOn: "天然矿泉水 550ml"
- assertVisible: "商品详情"
- tapOn: "加入购物车"

- runFlow:                       # 可能的加购弹窗,条件点掉
    when:
      visible: "继续购物"
    commands:
      - tapOn: "去结算"

- tapOn: "购物车"
- tapOn: "去结算"
- assertVisible: "确认订单"
- tapOn: "提交订单"
- assertVisible: "订单提交成功"
- screenshot: order_success

运行:

maestro test --format junit -e APP_ID=com.shop.android flows/smoke_order.yaml

场景延伸 1:跨 App / 系统设置(Maestro 的强项)

白盒框架最头疼的"操作设备本身",在 Maestro 里就是普通命令:

- toggleAirplaneMode
- toggleWifi
- tapOn: "飞行模式"            # 直接操作系统设置页
- openLink: "shop://product/123"   # 深链拉起
能力说明
操作系统设置改 WiFi、飞行模式、亮度,等同真人操作
读/处理通知可在通知层面操作(真机/模拟器)
跨 App可拉起别的 App 再回来,适合分享/支付/地图跳转

场景延伸 2:WebView 混合页与 Web

场景配置说明
App 内 WebView无需切上下文Maestro 直接按渲染出的文字操作,不必像 Appium 那样 switch context
纯网页url: https://example.com同一套 YAML 语法
url: https://example.com
---
- launchApp
- tapOn: "More information..."
- assertVisible: "Further Reading"

场景延伸 3:复杂列表与滚动

- scrollUntilVisible:
    element: "已到底部"
    direction: DOWN
    timeout: 20000
    visibility: 90%        # 元素可见比例达到才算命中

场景延伸 4:CI 集成(GitHub Actions 示例)

name: Maestro E2E
on: [push]
jobs:
  android-e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install & run
        uses: mobile-dev-inc/action-maestro-cloud@v1
        with:
          api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
          app-file: app/build/outputs/apk/debug/app-debug.apk
          flow-file: flows
本地 CI 方式做法
自建模拟器CI 机器起 Android 模拟器后 maestro test flows/
Maestro Cloud上传 APK + flows,云端多机并行,回传报告

AI 时代的玩法:让 AI 写并运行 Flow

Maestro CLI 内置了一个 MCP Server,AI 编程助手可以直接操作真实设备:

claude mcp add maestro -- maestro mcp
提供的 9 类工具(节选)用途
list_devices列出并选择目标设备
inspect_screen读取当前视图层级
run执行内联 YAML 或整个 flow 目录
take_screenshot截图(便于贴 PR)
cheat_sheet查询 Maestro 语法
open_maestro_viewer镜像设备屏幕
run_on_cloud / get_cloud_run_status提交云端并查状态

支持 Claude Code、Cursor、Copilot、Gemini 等。典型用法:你说"登录、把巴黎加入收藏、重启后确认还在",AI 写 Flow、真机执行、选择器失效时自己 inspect 后修正。Maestro Studio 内也有 AI 辅助(MaestroGPT)。


04 环境搭建与版本演进

环境清单(本地最容易翻车的几样)

AndroidiOS
前置工具平台工具 / adb,设备开 USB 调试Xcode + 命令行工具、模拟器
Maestro 本体一个 CLI,无需驱动/SDK 配置同一个 CLI
本地真机✅ 支持❌ 仅模拟器,真机走 Cloud
系统要求macOS/Linux/Windows 均可仅 macOS

CLI 安装

# macOS / Linux
curl -Ls "https://get.maestro.mobile.dev" | bash

# 升级
maestro upgrade
检查项命令
版本maestro --version
设备连通maestro devices
试运行maestro test flows/smoke_order.yaml

Studio / Viewer / Cloud 三件套

工具形态作用
Maestro Studio免费桌面 IDE(mac/Win/Linux)可视化构建、元素检查器、点击生成命令、MaestroGPT
Maestro Viewer设备镜像实时镜像当前设备屏幕,便于观察与调试
Maestro Cloud云端服务多设备并行、真机 iOS、企业级报告、CI 集成

版本演进与商业模式

维度现状
开源核心框架开源免费(Kotlin),本地无限跑
维护方mobile.dev(公司化运营,非个人项目,迭代活跃)
当前版本CLI 2.10.0(2026-08-31)
Cloud 定价(参考)移动端约 $250/设备/月,Web 约 $125/浏览器/月;企业定制(SSO/托管)
真实收益案例Wahed 用例编写从 3–4 小时降到 10–15 分钟;Eneco 回归从 16 小时降到 1 小时内;Komoot 两周建 100+ 用例

数据来自 Maestro 官方 benchmark / insights 页面,引用时建议标注"官方口径"。


05 稳定性治理:自动抗 flaky 的能力边界

自动等待是 Maestro 的招牌,但它不是万能。这一章讲清楚边界,避免"以为写了 YAML 就不会 flaky"。

1. 自动同步的边界

它能自动搞定它搞不定 / 需要你处理
等元素出现、等 UI settle业务语义错误(文案对但意思错)
等渲染、动画、网络回落极快闪过的瞬时元素
默认重试动作依赖外部第三方 App 状态的步骤
WebView 直接按文字操作Canvas/自绘 UI 里没有无障碍信息的元素

2. 语义定位 vs XPath/坐标

定位方式抗改版建议
文字 / 无障碍标签首选
id推动开发加稳定 id
关系定位文字重复时用
坐标 / XPath最后手段,最易 flaky

3. 重试与超时配置

- tapOn:
    text: "提交"
    retryTapIfNoChange: true   # 点击后界面没变则重试
    timeout: 10000
- extendTimeout: 30000          # 单步延长超时
手段场景
retryTapIfNoChange点击偶发不响应
timeout某元素加载偏慢
extendTimeout大文件/长流程

4. 用 clearState 做隔离

- launchApp:
    clearState: true      # 等同 adb shell pm clear,给"首次安装"状态
作用说明
消除缓存Android App 常缓存数据导致 flaky
可重复保证每次起点一致,便于并行

5. iOS 物理机限制(必须提前知道)

目标本地备选
iOS 模拟器
iOS 真机Maestro Cloud 或第三方真机云

如果团队强依赖"本地插真机调试 iOS",这条限制要在选型时就摆上桌。

6. 常见坑速查

现象处理
无障碍信息缺失自绘/游戏 UI 找不到元素推动加 accessibility label,或退坐标
文字重复tapOn 命中多个加 id 或关系定位缩小范围
键盘遮挡输入后点不到按钮hideKeyboard 后再点
启动动画/弹窗首屏脚本偶发失败when 条件处理引导/权限弹窗
国产机保活(真机)后台执行中断保持设备唤醒、关闭省电策略(CI 真机场景)
WebView 异步内容晚到语义断言本身会等,必要时加 timeout

06 优势与劣势

优势

优势说明
上手极快单二进制、零驱动、5–6 行 YAML 出第一条用例,学习约以天计
谁都能写手工 QA、PM 可直接维护,降低对 SDET 的依赖
默认抗 flaky自动等待 + 自动重试,少写大量样板代码
一套 YAML 三端Android/iOS/Web 同语法,混合 App(RN/Flutter)尤其舒服
零插桩不改 App、不加依赖、不编译测试包
驾驶整台设备系统设置、通知、跨 App 都是常规操作
AI 原生内置 MCP,可让 AI 直接写并执行用例
免费核心本地无限跑,小团队零成本起步

劣势

劣势说明
iOS 真机本地不支持必须 Cloud,强本地真机团队受限
表达能力有上限超复杂逻辑要靠 JS,且仍不如全语言灵活
黑盒速度略慢每步 dump 视图树,不及白盒进程内直连快
平台广度不及 Appium不覆盖 Windows/macOS/TV 等
依赖语义/无障碍自绘 UI、无 label 的元素定位困难
云能力付费规模化并行/真机 iOS 需订阅 Cloud
调试生态不如 Appium/XCUITest 与 IDE 深度集成成熟

07 选型建议:什么项目该用 Maestro

决策表

项目特征推荐理由
小团队、追求快速铺开移动端 E2E✅ Maestro上手快、零配置、默认稳定
手工测试/PM 也要维护用例✅ MaestroYAML 无编程门槛
RN / Flutter / Compose 跨端,想一套脚本✅ Maestro框架无关、一套 YAML
经常测跨 App、系统设置、通知✅ Maestro设备级驾驶是强项
想用 AI 自动写跑用例✅ Maestro内置 MCP
Android 单 App 深度高频回归➡ Espresso同进程更快、白盒更强
iOS 本地插真机为主➡ XCUITest 或 AppiumMaestro 真机需 Cloud
已有 Selenium/Appium 多语言体系与 POM➡ Appium统一语言与模型的组织价值更大
需要覆盖 Win/macOS/TV➡ AppiumMaestro 不覆盖
React Native 灰盒同步➡ Detox(备选)状态同步更贴合 RN

系列 7 框架总选型表

#框架平台运行位置脚本形态上手成本自动等待iOS 真机跨 App/系统适合谁
01SeleniumWeb进程外(HTTP/WebDriver)多语言自己写SDET/测试团队
02PlaywrightWeb进程外(CDP 直连)多语言前端/SDET
03CypressWeb浏览器进程内JS前端
04EspressoAndroidApp 进程内Java/Kotlin同步Android 开发
05Appium全平台进程外黑盒多语言自己写SDET
06XCUITestiOS独立进程白盒SwiftiOS 开发
07MaestroAndroid/iOS/Web进程外黑盒YAML(+JS)极低✅+重试❌(需Cloud)全员/QA/PM

表外补充:Detox 专做 React Native(iOS/Android、灰盒、JS/TS),状态同步更贴合 RN,RN 重度团队可单独评估,不属于本系列 7 篇主线。

一句话结论

你的处境选择
想要"少折腾、快速见效、人人能写、还能让 AI 帮忙"的移动端 E2EMaestro
要最大平台/语言自由度和企业级统一体系Appium
单端深度回归、追求极限速度Espresso(安卓)/ XCUITest(iOS)

Maestro 的本质不是"更简单的 Appium",而是把"等待、重试、同步"这些本该由框架负责的事从测试者手里收回去——你只负责描述意图,剩下的交给它。 在 AI 写测试成为常态的 2026 年,这种"声明意图 + 机器执行"的形态,反而比"人写命令式代码"更顺。


参考资料

资料链接
Maestro 官方文档(Flows 概述)https://docs.maestro.dev/maestro-flows/
Maestro 官方站点https://maestro.dev/
Android 平台说明https://docs.maestro.dev/get-started/supported-platform/android
Maestro vs Appium 官方 Benchmarkhttps://maestro.dev/blog/maestro-vs-appium-the-benchmark
GitHub 仓库(版本/Star)https://github.com/mobile-dev-inc/maestro
最佳移动测试框架对比(官方 insights)https://maestro.dev/insights/best-automated-testing-frameworks-mobile-apps
Maestro Cloud 说明https://docs.maestro.dev/maestro-cloud/
Logo

一站式 AI 云服务平台

更多推荐