1. 项目概述为什么是Maestro如果你正在为移动应用的UI自动化测试而头疼觉得Appium太笨重维护成本高或者觉得原生框架写起来太繁琐那么Maestro这个工具的出现很可能就是你的“及时雨”。我最初接触Maestro是在一个需要快速验证十几个核心用户路径的紧急项目中Appium的脚本因为应用的一次小更新而大面积失效团队陷入了“修脚本比开发新功能还慢”的窘境。当时一个同事丢给我一个GitHub链接说“试试这个号称是下一代移动UI自动化框架”。抱着死马当活马医的心态我花了一个下午研究结果当天晚上就用它跑通了所有核心流程并且脚本的稳定性和可读性远超预期。Maestro的核心魅力在于它的“声明式”语法和“平台无关”的设计。它不像Appium那样需要你处理复杂的WebDriver协议、各种Capability配置和等待策略。Maestro的脚本我们称之为flow.yaml读起来就像一份清晰的测试用例清单“点击这个ID的按钮”、“在这个输入框里输入文字”、“断言这个文本存在”。它底层基于Facebook的idbiOS和Google的adbAndroid直接与设备通信绕过了WebDriver的中间层这带来了两个直接好处执行速度更快对应用UI变化的适应性更强。特别是对于Flutter、React Native等跨平台应用你只需要写一套YAML脚本就能同时在iOS和Android上运行这极大地提升了测试效率。所以这个“5步掌握核心技能”的实战教程目的不是让你成为Maestro的专家而是让你能快速上手在最短的时间内将Maestro应用到你的实际项目中解决UI自动化测试中的痛点。无论你是测试开发工程师、移动开发工程师还是对质量保障感兴趣的任何人只要跟着这五步走你就能建立起一套可用的、易维护的自动化测试能力。2. 环境搭建与初识Maestro CLI工欲善其事必先利其器。Maestro的安装过程极其简单这本身也体现了其设计哲学降低使用门槛。2.1 安装MaestroMaestro主要通过命令行工具maestro来驱动它的安装方式多样最推荐的是使用包管理工具。对于macOS用户这也是移动开发的主流平台使用Homebrew是最快捷的方式。打开你的终端输入以下命令brew install maestro安装完成后在终端输入maestro --version如果能看到版本号输出例如Maestro version 1.30.0说明安装成功。对于其他平台Linux/WindowsMaestro提供了安装脚本。在终端中运行curl -Ls “https://get.maestro.mobile.dev” | bash这个脚本会自动下载并配置。对于Windows用户也可以通过WSL2Windows Subsystem for Linux来获得类似macOS/Linux的终端体验然后在WSL中运行上述脚本。注意无论哪种方式请确保你的系统已经安装了Java Runtime Environment (JRE) 11或更高版本因为Maestro的某些组件依赖Java。可以通过java -version来检查。2.2 连接测试设备Maestro需要与真实的移动设备或模拟器/仿真器进行交互。这里以iOS模拟器和Android模拟器为例。iOS设备连接确保Xcode已安装。打开Xcode进入Xcode - Settings - Platforms安装你需要的iOS模拟器版本。启动一个iOS模拟器。可以在终端用命令open -a Simulator打开也可以在Xcode的Window - Devices and Simulators中启动。在终端中运行maestro test ios。Maestro会自动检测到已启动的模拟器并列出其UDID。首次运行可能会提示你信任开发者证书在模拟器上点击“信任”即可。Android设备连接确保Android SDK已安装并且adb(Android Debug Bridge) 工具在系统路径中。可以通过adb devices命令检查。启动一个Android模拟器例如通过Android Studio的AVD Manager。在终端中运行adb devices确认你的模拟器或真机出现在设备列表中状态为device。运行maestro test androidMaestro会识别到通过adb连接的设备。一个关键的实操心得我强烈建议在开始编写复杂脚本前先使用maestro studio命令。这是一个交互式的录制工具。运行后它会启动一个本地服务器并生成一个二维码。用手机摄像头扫描这个二维码手机和电脑需在同一网络之后你在手机上的所有操作都会被实时录制并生成对应的YAML脚本片段。这对于学习Maestro的语法和快速生成基础脚本非常有帮助尤其是定位元素时。2.3 Maestro CLI核心命令解析安装成功后我们来熟悉几个最常用的CLI命令这是你与Maestro交互的主要方式maestro test flow.yaml运行指定的测试流程文件。这是最核心的命令。maestro test directory运行指定目录下的所有YAML流程文件。maestro studio启动交互式录制工作室如上所述。maestro upload将测试结果上传到Maestro Cloud进行可视化报告查看需要登录。maestro --help查看所有可用命令和帮助信息。参数使用示例 如果你想在特定的iOS设备上运行测试可以这样maestro test —device ios:你的设备UDID flow.yaml如果你想运行测试并生成一个JUnit格式的报告便于集成到CI/CD中可以maestro test —format junit flow.yaml test-report.xml环境搭建完毕并且对CLI有了基本认识后我们就可以开始动手创建第一个自动化测试脚本了。记住Maestro的学习曲线很平缓很多复杂问题都通过优雅的设计简化了。3. 编写你的第一个Flow脚本从登录场景开始理论说再多不如动手写一行。让我们从一个最常见的移动应用场景开始用户登录。假设我们有一个简单的登录界面包含用户名输入框、密码输入框和登录按钮。3.1 创建Flow文件与基础结构首先在你项目的合适位置例如tests/目录下创建一个YAML文件命名为login_flow.yaml。Maestro的脚本文件以.yaml或.yml为后缀。打开这个文件我们开始编写第一个Flow。一个最基本的Flow结构如下appId: com.yourcompany.yourapp # 目标应用的包名(Bundle ID)或应用ID --- - launchApp # 指令1启动应用appId这是Flow的全局配置指定你要测试哪个应用。对于iOS是Bundle Identifier如com.yourapp.ios对于Android是Package Name如com.yourapp.android。这是必填项Maestro靠它来定位和操作应用。---YAML的分隔符用于区分配置部分和指令列表部分。- launchApp这是一个指令Command。每条指令以-开头。launchApp指令会启动在appId中指定的应用。现在你可以在终端运行maestro test login_flow.yaml看看应用是否被成功启动。如果一切正常模拟器上的应用会被打开。3.2 元素定位与交互指令应用启动后我们需要操作界面元素。Maestro提供了多种灵活的元素定位方式这是其强大易用的关键。1. 定位登录输入框并输入文本假设我们的用户名输入框在UI层级中有一个唯一的id属性usernameField。在launchApp指令后添加- tapOn: “usernameField” # 点击用户名输入框 - inputText: “testuserexample.com” # 输入文本tapOn是点击指令。Maestro会尝试通过多种策略优先级顺序id text 其他来查找屏幕上匹配“usernameField”的元素并点击它。随后inputText指令会将指定的文本输入到当前焦点所在的位置即刚刚点击的输入框。如果元素没有ID怎么办更常见的情况是我们通过屏幕上显示的文本来定位。假设密码输入框旁边有文本标签“Password”- tapOn: “Password” # 点击“Password”文本所在的元素通常是输入框本身或其父容器 - inputText: “MySecretPass123!” # 输入密码 - hideKeyboard # 一个非常实用的指令隐藏软键盘这里tapOn: “Password”会寻找屏幕上任何包含“Password”文本的视图并进行点击。hideKeyboard指令在输入完成后调用可以确保键盘不会遮挡后续需要操作或断言的元素。2. 定位并点击登录按钮登录按钮上可能有文字“Log In”或“Sign In”。我们使用tapOn来点击它- tapOn: “Log In”3.3 添加断言验证结果自动化测试的灵魂在于验证。点击登录按钮后我们需要断言登录是否成功。成功的标志可能是跳转到主页并且主页上显示用户的昵称“Welcome, John”。我们可以使用assertVisible指令- assertVisible: “Welcome, John” # 断言文本“Welcome, John”在屏幕上可见这条指令会等待一段时间默认超时时间可配置直到指定的文本出现在屏幕上。如果超时后仍未出现测试将失败。更复杂的断言场景有时我们需要断言某个元素不存在比如登录失败后的错误提示不应该出现。可以使用assertNotVisible- assertNotVisible: “Invalid credentials” # 断言错误提示信息不可见现在我们完整的login_flow.yaml脚本如下appId: com.yourcompany.yourapp --- - launchApp - tapOn: “usernameField” - inputText: “testuserexample.com” - tapOn: “Password” - inputText: “MySecretPass123!” - hideKeyboard - tapOn: “Log In” - assertVisible: “Welcome, John”运行这个脚本你将会看到Maestro自动执行登录流程并在最后验证结果。一个重要的注意事项在实际项目中直接向脚本硬编码敏感信息如密码是不安全的。Maestro支持环境变量。你可以这样改进- inputText: “${USERNAME}” - inputText: “${PASSWORD}”然后在运行命令时传入USERNAMEtestuser PASSWORDsecret maestro test login_flow.yaml。或者在项目根目录创建.env文件来管理这些变量。通过这个简单的登录Flow你已经掌握了Maestro最核心的指令启动应用、定位元素通过id或text、交互点击、输入和断言。接下来我们将探索如何用更强大的指令来构建复杂的用户旅程。4. 构建复杂用户旅程条件逻辑、数据驱动与复用掌握了基础指令后你会发现很多真实的用户场景比简单的线性流程要复杂。比如用户可能已经是登录状态我们需要跳过登录或者我们需要用多组数据测试登录功能又或者很多流程如添加到购物车、结算会在多个测试用例中重复。Maestro提供了高级功能来优雅地处理这些情况。4.1 使用条件逻辑runFlow与assertVisible结合假设我们的应用在启动时如果检测到已有有效登录令牌会直接进入主页否则会显示登录界面。我们需要一个智能的Flow来处理这两种情况。我们可以利用assertVisible的等待机制和runFlow指令来实现条件执行appId: com.yourcompany.yourapp --- - launchApp - assertVisible: visible: “Welcome, John” # 情况1尝试断言主页元素 timeout: 5000 # 等待5秒 if: “visible” # 如果5秒内找到了“Welcome, John” then: # 那么执行以下指令说明已登录 - stopApp # 可以停止应用或者开始执行主页的后续测试 else: # 否则没找到说明在登录页 - runFlow: “login_flow.yaml” # 执行登录子流程这段脚本的逻辑是启动应用后立即检查主页元素是否在5秒内出现。如果出现则执行then块内的指令这里只是停止了应用实际中可能是开始主页测试。如果没出现即超时则执行else块内的指令即运行我们之前写好的login_flow.yaml子流程来完成登录。runFlow指令是模块化的关键它允许你将通用的流程如登录、登出、添加商品到购物车抽离成独立的YAML文件然后在主Flow中调用极大地提高了脚本的可维护性和复用性。4.2 实现数据驱动测试数据驱动测试DDT是自动化测试的进阶技能它允许你用同一套脚本逻辑测试多组输入数据。Maestro通过env和循环概念结合外部工具或脚本来支持但更直观的方式是利用其与命令行交互的能力。一种实用的方法是创建一个包含多组测试数据的YAML文件例如test_data.yamlcredentials: - username: “user1test.com” password: “pass1” expectedWelcome: “Welcome, User1” - username: “user2test.com” password: “pass2” expectedWelcome: “Welcome, User2” - username: “wronguser.com” password: “wrong” expectedError: “Invalid credentials”然后你可以编写一个通用的登录Flow (generic_login.yaml)它使用环境变量appId: com.yourcompany.yourapp --- - launchApp - tapOn: “usernameField” - inputText: “${USERNAME}” - tapOn: “Password” - inputText: “${PASSWORD}” - hideKeyboard - tapOn: “Log In” - assertVisible: “${EXPECTED_TEXT}” # 这里可以是欢迎语或错误信息最后编写一个Shell脚本如run_data_driven.sh来循环执行#!/bin/bash # 这是一个简化示例实际中你可能需要用yq或jq来解析YAML数据 USERNAME“user1test.com” PASSWORD“pass1” EXPECTED_TEXT“Welcome, User1” maestro test generic_login.yaml USERNAME“user2test.com” PASSWORD“pass2” EXPECTED_TEXT“Welcome, User2” maestro test generic_login.yaml # 测试错误情况 USERNAME“wronguser.com” PASSWORD“wrong” EXPECTED_TEXT“Invalid credentials” maestro test generic_login.yaml通过这种方式你虽然需要一些外围的脚本支持但核心的Maestro测试逻辑保持了简洁和复用性。在CI/CD流水线中你可以轻松地读取外部数据源如CSV、JSON来动态设置环境变量。4.3 流程复用与模块化设计随着测试套件增长模块化设计至关重要。除了使用runFlow你还可以利用Maestro的config块来定义全局变量和默认行为。例如在项目的根目录创建一个config.yamlappId: com.yourcompany.yourapp defaultTimeout: 30000 # 全局默认超时时间设为30秒 env: BASE_URL: “https://api.yourapp.com”然后在各个子Flow中你不再需要重复定义appIdMaestro会自动继承或合并配置。你可以在子Flow中通过${BASE_URL}来引用环境变量。一个常见的目录结构建议e2e-tests/ ├── config.yaml # 全局配置 ├── flows/ │ ├── common/ │ │ ├── login.yaml │ │ └── logout.yaml │ ├── features/ │ │ ├── checkout_flow.yaml │ │ └── search_flow.yaml │ └── smoke_test_suite.yaml # 主入口通过runFlow组合各个feature ├── test_data/ │ └── credentials.yaml └── run_tests.sh # 封装测试执行命令的脚本这样的结构清晰地将配置、公共操作、特性流程和数据分离开无论是维护还是新增测试用例都更加高效。5. 高级技巧与实战调试当你能够编写和运行基本的Flow后接下来会遇到一些更实际的问题如何定位那些没有文本、ID也不稳定的元素测试失败了如何快速定位问题如何让测试运行得更稳定这一章我们来解决这些进阶问题。5.1 高级元素定位策略当id和text都无法精确定位时Maestro提供了更强大的定位器。1. 使用point进行绝对坐标点击最后的手段- tapOn: point: “50%, 30%” # 点击屏幕水平50%垂直30%的位置警告绝对坐标定位是脆弱的在不同分辨率或UI布局变化时极易失败。仅在万不得已时使用例如点击一个没有任何标识的空白区域或自定义绘制的图形按钮。优先考虑其他定位方式。2. 使用relativePoint进行相对坐标点击比绝对坐标稍好一些它基于某个已定位元素的相对位置。- tapOn: “SomeElement” - tapOn: relativePoint: “50%, 100%” # 在“SomeElement”元素的底部中心点点击这在你需要点击一个元素内部特定区域时有用。3. 使用index处理多个相同元素如果屏幕上有多个“Add to Cart”按钮你可以用索引来指定点击第几个。- tapOn: text: “Add to Cart” index: 2 # 点击第二个匹配到的“Add to Cart”按钮索引从0开始4. 组合定位器提高精度你可以组合多个属性来精确定位。- tapOn: id: “action_button” text: “Confirm” enabled: true # 只点击处于启用状态的按钮这个指令会寻找一个ID为action_button、文本是Confirm并且处于启用状态的元素精准度非常高。实操心得利用maestro studio和 App Inspector。当你不确定如何定位一个元素时最好的方法是运行maestro studio录制你的操作它会生成包含定位信息的YAML片段这是最直接的学习方式。使用Xcode的Accessibility Inspector或Android Studio的Layout Inspector来查看UI层级获取元素更详细的属性如content-descAndroid、accessibilityIdentifieriOS这些都可以作为Maestro的定位依据。5.2 调试与日志分析测试失败是常态高效的调试能力是关键。1. 增加详细日志输出运行测试时使用-v(verbose) 标志可以输出更详细的执行日志。maestro test -v my_flow.yaml你会看到Maestro每一步在做什么寻找什么元素等待了多久这对于理解测试卡在哪里至关重要。2. 使用-e参数保留测试后的应用状态默认情况下测试结束后Maestro会清理环境。但调试时你可能希望看到失败那一刻的屏幕状态。maestro test -e my_flow.yaml测试失败后应用不会被关闭你可以手动检查屏幕上的UI。3. 分析Maestro生成的报告Maestro在运行后会生成一个简洁的终端报告显示通过/失败的测试。但更强大的是你可以使用maestro upload命令将结果上传到Maestro Cloud需要注册账号。Maestro Cloud提供了可视化的时间线报告你可以看到每一步的截图、视频回放和日志像看监控录像一样复盘测试执行过程这是定位偶发性问题如竞态条件的神器。4. 处理不稳定元素与智能等待UI自动化最大的敌人是“不稳定”——元素加载有时快有时慢。Maestro内置了智能等待机制在每次交互指令如tapOn,inputText前都会等待目标元素出现默认超时时间。你可以通过defaultTimeout全局配置或为单个指令设置timeout来调整。- tapOn: id: “slowLoadingButton” timeout: 10000 # 为此点击操作单独设置10秒超时此外scrollUntilVisible指令在列表或滚动视图中查找元素时非常有用它会自动滚动直到目标元素出现。5.3 集成到CI/CD流水线自动化测试只有集成到持续集成/持续部署流程中才能发挥最大价值。将Maestro集成到CI/CD如GitHub Actions, Jenkins, GitLab CI中非常直接。一个GitHub Actions工作流的示例 (.github/workflows/maestro-tests.yml)name: Maestro E2E Tests on: [push, pull_request] jobs: test: runs-on: macos-latest # 需要macOS来运行iOS模拟器 steps: - uses: actions/checkoutv3 - name: Setup Java uses: actions/setup-javav3 with: java-version: ‘11’ - name: Install Maestro run: | curl -Ls “https://get.maestro.mobile.dev” | bash echo “$HOME/.maestro/bin” $GITHUB_PATH - name: Start iOS Simulator run: | xcrun simctl boot “iPhone 14” || true - name: Run Maestro Tests run: | maestro test —format junit flows/ test-results.xml env: USERNAME: ${{ secrets.TEST_USERNAME }} PASSWORD: ${{ secrets.TEST_PASSWORD }} - name: Upload Test Results uses: actions/upload-artifactv3 if: always() with: name: maestro-junit-results path: test-results.xml这个工作流做了以下几件事1) 准备macOS环境2) 安装Maestro3) 启动一个iOS模拟器4) 运行所有Flow并生成JUnit报告5) 将报告上传为制品。你可以将JUnit报告与GitHub的代码检查或其他仪表板集成。在CI中的稳定性技巧使用可靠的模拟器/设备镜像在CI中指定一个稳定版本的模拟器避免使用最新的Beta版。测试前清理状态在运行测试前使用maestro stopApp或adb shell am force-stop等命令确保应用是从干净状态启动。处理依赖服务确保你的CI环境能访问测试所需的后端API或Mock服务。设置合理的超时和重试对于整个测试套件在CI配置中设置一个全局超时。对于不稳定的测试可以考虑在Flow级别或通过CI脚本进行有限次数的重试。通过以上五个步骤——从环境搭建、编写第一个Flow、构建复杂逻辑、到高级调试和CI集成——你已经系统地掌握了Maestro移动UI自动化测试的核心技能。这套方法能帮助你快速为项目引入可靠、易维护的端到端测试将团队从繁琐的手工回归测试中解放出来更专注于创造价值。记住所有工具都是为了解决问题而存在Maestro的优势在于它的简洁和高效当你被其他框架的复杂性困扰时它值得你一试。
5步掌握Maestro:下一代移动UI自动化测试框架实战指南
发布时间:2026/6/30 20:40:25
1. 项目概述为什么是Maestro如果你正在为移动应用的UI自动化测试而头疼觉得Appium太笨重维护成本高或者觉得原生框架写起来太繁琐那么Maestro这个工具的出现很可能就是你的“及时雨”。我最初接触Maestro是在一个需要快速验证十几个核心用户路径的紧急项目中Appium的脚本因为应用的一次小更新而大面积失效团队陷入了“修脚本比开发新功能还慢”的窘境。当时一个同事丢给我一个GitHub链接说“试试这个号称是下一代移动UI自动化框架”。抱着死马当活马医的心态我花了一个下午研究结果当天晚上就用它跑通了所有核心流程并且脚本的稳定性和可读性远超预期。Maestro的核心魅力在于它的“声明式”语法和“平台无关”的设计。它不像Appium那样需要你处理复杂的WebDriver协议、各种Capability配置和等待策略。Maestro的脚本我们称之为flow.yaml读起来就像一份清晰的测试用例清单“点击这个ID的按钮”、“在这个输入框里输入文字”、“断言这个文本存在”。它底层基于Facebook的idbiOS和Google的adbAndroid直接与设备通信绕过了WebDriver的中间层这带来了两个直接好处执行速度更快对应用UI变化的适应性更强。特别是对于Flutter、React Native等跨平台应用你只需要写一套YAML脚本就能同时在iOS和Android上运行这极大地提升了测试效率。所以这个“5步掌握核心技能”的实战教程目的不是让你成为Maestro的专家而是让你能快速上手在最短的时间内将Maestro应用到你的实际项目中解决UI自动化测试中的痛点。无论你是测试开发工程师、移动开发工程师还是对质量保障感兴趣的任何人只要跟着这五步走你就能建立起一套可用的、易维护的自动化测试能力。2. 环境搭建与初识Maestro CLI工欲善其事必先利其器。Maestro的安装过程极其简单这本身也体现了其设计哲学降低使用门槛。2.1 安装MaestroMaestro主要通过命令行工具maestro来驱动它的安装方式多样最推荐的是使用包管理工具。对于macOS用户这也是移动开发的主流平台使用Homebrew是最快捷的方式。打开你的终端输入以下命令brew install maestro安装完成后在终端输入maestro --version如果能看到版本号输出例如Maestro version 1.30.0说明安装成功。对于其他平台Linux/WindowsMaestro提供了安装脚本。在终端中运行curl -Ls “https://get.maestro.mobile.dev” | bash这个脚本会自动下载并配置。对于Windows用户也可以通过WSL2Windows Subsystem for Linux来获得类似macOS/Linux的终端体验然后在WSL中运行上述脚本。注意无论哪种方式请确保你的系统已经安装了Java Runtime Environment (JRE) 11或更高版本因为Maestro的某些组件依赖Java。可以通过java -version来检查。2.2 连接测试设备Maestro需要与真实的移动设备或模拟器/仿真器进行交互。这里以iOS模拟器和Android模拟器为例。iOS设备连接确保Xcode已安装。打开Xcode进入Xcode - Settings - Platforms安装你需要的iOS模拟器版本。启动一个iOS模拟器。可以在终端用命令open -a Simulator打开也可以在Xcode的Window - Devices and Simulators中启动。在终端中运行maestro test ios。Maestro会自动检测到已启动的模拟器并列出其UDID。首次运行可能会提示你信任开发者证书在模拟器上点击“信任”即可。Android设备连接确保Android SDK已安装并且adb(Android Debug Bridge) 工具在系统路径中。可以通过adb devices命令检查。启动一个Android模拟器例如通过Android Studio的AVD Manager。在终端中运行adb devices确认你的模拟器或真机出现在设备列表中状态为device。运行maestro test androidMaestro会识别到通过adb连接的设备。一个关键的实操心得我强烈建议在开始编写复杂脚本前先使用maestro studio命令。这是一个交互式的录制工具。运行后它会启动一个本地服务器并生成一个二维码。用手机摄像头扫描这个二维码手机和电脑需在同一网络之后你在手机上的所有操作都会被实时录制并生成对应的YAML脚本片段。这对于学习Maestro的语法和快速生成基础脚本非常有帮助尤其是定位元素时。2.3 Maestro CLI核心命令解析安装成功后我们来熟悉几个最常用的CLI命令这是你与Maestro交互的主要方式maestro test flow.yaml运行指定的测试流程文件。这是最核心的命令。maestro test directory运行指定目录下的所有YAML流程文件。maestro studio启动交互式录制工作室如上所述。maestro upload将测试结果上传到Maestro Cloud进行可视化报告查看需要登录。maestro --help查看所有可用命令和帮助信息。参数使用示例 如果你想在特定的iOS设备上运行测试可以这样maestro test —device ios:你的设备UDID flow.yaml如果你想运行测试并生成一个JUnit格式的报告便于集成到CI/CD中可以maestro test —format junit flow.yaml test-report.xml环境搭建完毕并且对CLI有了基本认识后我们就可以开始动手创建第一个自动化测试脚本了。记住Maestro的学习曲线很平缓很多复杂问题都通过优雅的设计简化了。3. 编写你的第一个Flow脚本从登录场景开始理论说再多不如动手写一行。让我们从一个最常见的移动应用场景开始用户登录。假设我们有一个简单的登录界面包含用户名输入框、密码输入框和登录按钮。3.1 创建Flow文件与基础结构首先在你项目的合适位置例如tests/目录下创建一个YAML文件命名为login_flow.yaml。Maestro的脚本文件以.yaml或.yml为后缀。打开这个文件我们开始编写第一个Flow。一个最基本的Flow结构如下appId: com.yourcompany.yourapp # 目标应用的包名(Bundle ID)或应用ID --- - launchApp # 指令1启动应用appId这是Flow的全局配置指定你要测试哪个应用。对于iOS是Bundle Identifier如com.yourapp.ios对于Android是Package Name如com.yourapp.android。这是必填项Maestro靠它来定位和操作应用。---YAML的分隔符用于区分配置部分和指令列表部分。- launchApp这是一个指令Command。每条指令以-开头。launchApp指令会启动在appId中指定的应用。现在你可以在终端运行maestro test login_flow.yaml看看应用是否被成功启动。如果一切正常模拟器上的应用会被打开。3.2 元素定位与交互指令应用启动后我们需要操作界面元素。Maestro提供了多种灵活的元素定位方式这是其强大易用的关键。1. 定位登录输入框并输入文本假设我们的用户名输入框在UI层级中有一个唯一的id属性usernameField。在launchApp指令后添加- tapOn: “usernameField” # 点击用户名输入框 - inputText: “testuserexample.com” # 输入文本tapOn是点击指令。Maestro会尝试通过多种策略优先级顺序id text 其他来查找屏幕上匹配“usernameField”的元素并点击它。随后inputText指令会将指定的文本输入到当前焦点所在的位置即刚刚点击的输入框。如果元素没有ID怎么办更常见的情况是我们通过屏幕上显示的文本来定位。假设密码输入框旁边有文本标签“Password”- tapOn: “Password” # 点击“Password”文本所在的元素通常是输入框本身或其父容器 - inputText: “MySecretPass123!” # 输入密码 - hideKeyboard # 一个非常实用的指令隐藏软键盘这里tapOn: “Password”会寻找屏幕上任何包含“Password”文本的视图并进行点击。hideKeyboard指令在输入完成后调用可以确保键盘不会遮挡后续需要操作或断言的元素。2. 定位并点击登录按钮登录按钮上可能有文字“Log In”或“Sign In”。我们使用tapOn来点击它- tapOn: “Log In”3.3 添加断言验证结果自动化测试的灵魂在于验证。点击登录按钮后我们需要断言登录是否成功。成功的标志可能是跳转到主页并且主页上显示用户的昵称“Welcome, John”。我们可以使用assertVisible指令- assertVisible: “Welcome, John” # 断言文本“Welcome, John”在屏幕上可见这条指令会等待一段时间默认超时时间可配置直到指定的文本出现在屏幕上。如果超时后仍未出现测试将失败。更复杂的断言场景有时我们需要断言某个元素不存在比如登录失败后的错误提示不应该出现。可以使用assertNotVisible- assertNotVisible: “Invalid credentials” # 断言错误提示信息不可见现在我们完整的login_flow.yaml脚本如下appId: com.yourcompany.yourapp --- - launchApp - tapOn: “usernameField” - inputText: “testuserexample.com” - tapOn: “Password” - inputText: “MySecretPass123!” - hideKeyboard - tapOn: “Log In” - assertVisible: “Welcome, John”运行这个脚本你将会看到Maestro自动执行登录流程并在最后验证结果。一个重要的注意事项在实际项目中直接向脚本硬编码敏感信息如密码是不安全的。Maestro支持环境变量。你可以这样改进- inputText: “${USERNAME}” - inputText: “${PASSWORD}”然后在运行命令时传入USERNAMEtestuser PASSWORDsecret maestro test login_flow.yaml。或者在项目根目录创建.env文件来管理这些变量。通过这个简单的登录Flow你已经掌握了Maestro最核心的指令启动应用、定位元素通过id或text、交互点击、输入和断言。接下来我们将探索如何用更强大的指令来构建复杂的用户旅程。4. 构建复杂用户旅程条件逻辑、数据驱动与复用掌握了基础指令后你会发现很多真实的用户场景比简单的线性流程要复杂。比如用户可能已经是登录状态我们需要跳过登录或者我们需要用多组数据测试登录功能又或者很多流程如添加到购物车、结算会在多个测试用例中重复。Maestro提供了高级功能来优雅地处理这些情况。4.1 使用条件逻辑runFlow与assertVisible结合假设我们的应用在启动时如果检测到已有有效登录令牌会直接进入主页否则会显示登录界面。我们需要一个智能的Flow来处理这两种情况。我们可以利用assertVisible的等待机制和runFlow指令来实现条件执行appId: com.yourcompany.yourapp --- - launchApp - assertVisible: visible: “Welcome, John” # 情况1尝试断言主页元素 timeout: 5000 # 等待5秒 if: “visible” # 如果5秒内找到了“Welcome, John” then: # 那么执行以下指令说明已登录 - stopApp # 可以停止应用或者开始执行主页的后续测试 else: # 否则没找到说明在登录页 - runFlow: “login_flow.yaml” # 执行登录子流程这段脚本的逻辑是启动应用后立即检查主页元素是否在5秒内出现。如果出现则执行then块内的指令这里只是停止了应用实际中可能是开始主页测试。如果没出现即超时则执行else块内的指令即运行我们之前写好的login_flow.yaml子流程来完成登录。runFlow指令是模块化的关键它允许你将通用的流程如登录、登出、添加商品到购物车抽离成独立的YAML文件然后在主Flow中调用极大地提高了脚本的可维护性和复用性。4.2 实现数据驱动测试数据驱动测试DDT是自动化测试的进阶技能它允许你用同一套脚本逻辑测试多组输入数据。Maestro通过env和循环概念结合外部工具或脚本来支持但更直观的方式是利用其与命令行交互的能力。一种实用的方法是创建一个包含多组测试数据的YAML文件例如test_data.yamlcredentials: - username: “user1test.com” password: “pass1” expectedWelcome: “Welcome, User1” - username: “user2test.com” password: “pass2” expectedWelcome: “Welcome, User2” - username: “wronguser.com” password: “wrong” expectedError: “Invalid credentials”然后你可以编写一个通用的登录Flow (generic_login.yaml)它使用环境变量appId: com.yourcompany.yourapp --- - launchApp - tapOn: “usernameField” - inputText: “${USERNAME}” - tapOn: “Password” - inputText: “${PASSWORD}” - hideKeyboard - tapOn: “Log In” - assertVisible: “${EXPECTED_TEXT}” # 这里可以是欢迎语或错误信息最后编写一个Shell脚本如run_data_driven.sh来循环执行#!/bin/bash # 这是一个简化示例实际中你可能需要用yq或jq来解析YAML数据 USERNAME“user1test.com” PASSWORD“pass1” EXPECTED_TEXT“Welcome, User1” maestro test generic_login.yaml USERNAME“user2test.com” PASSWORD“pass2” EXPECTED_TEXT“Welcome, User2” maestro test generic_login.yaml # 测试错误情况 USERNAME“wronguser.com” PASSWORD“wrong” EXPECTED_TEXT“Invalid credentials” maestro test generic_login.yaml通过这种方式你虽然需要一些外围的脚本支持但核心的Maestro测试逻辑保持了简洁和复用性。在CI/CD流水线中你可以轻松地读取外部数据源如CSV、JSON来动态设置环境变量。4.3 流程复用与模块化设计随着测试套件增长模块化设计至关重要。除了使用runFlow你还可以利用Maestro的config块来定义全局变量和默认行为。例如在项目的根目录创建一个config.yamlappId: com.yourcompany.yourapp defaultTimeout: 30000 # 全局默认超时时间设为30秒 env: BASE_URL: “https://api.yourapp.com”然后在各个子Flow中你不再需要重复定义appIdMaestro会自动继承或合并配置。你可以在子Flow中通过${BASE_URL}来引用环境变量。一个常见的目录结构建议e2e-tests/ ├── config.yaml # 全局配置 ├── flows/ │ ├── common/ │ │ ├── login.yaml │ │ └── logout.yaml │ ├── features/ │ │ ├── checkout_flow.yaml │ │ └── search_flow.yaml │ └── smoke_test_suite.yaml # 主入口通过runFlow组合各个feature ├── test_data/ │ └── credentials.yaml └── run_tests.sh # 封装测试执行命令的脚本这样的结构清晰地将配置、公共操作、特性流程和数据分离开无论是维护还是新增测试用例都更加高效。5. 高级技巧与实战调试当你能够编写和运行基本的Flow后接下来会遇到一些更实际的问题如何定位那些没有文本、ID也不稳定的元素测试失败了如何快速定位问题如何让测试运行得更稳定这一章我们来解决这些进阶问题。5.1 高级元素定位策略当id和text都无法精确定位时Maestro提供了更强大的定位器。1. 使用point进行绝对坐标点击最后的手段- tapOn: point: “50%, 30%” # 点击屏幕水平50%垂直30%的位置警告绝对坐标定位是脆弱的在不同分辨率或UI布局变化时极易失败。仅在万不得已时使用例如点击一个没有任何标识的空白区域或自定义绘制的图形按钮。优先考虑其他定位方式。2. 使用relativePoint进行相对坐标点击比绝对坐标稍好一些它基于某个已定位元素的相对位置。- tapOn: “SomeElement” - tapOn: relativePoint: “50%, 100%” # 在“SomeElement”元素的底部中心点点击这在你需要点击一个元素内部特定区域时有用。3. 使用index处理多个相同元素如果屏幕上有多个“Add to Cart”按钮你可以用索引来指定点击第几个。- tapOn: text: “Add to Cart” index: 2 # 点击第二个匹配到的“Add to Cart”按钮索引从0开始4. 组合定位器提高精度你可以组合多个属性来精确定位。- tapOn: id: “action_button” text: “Confirm” enabled: true # 只点击处于启用状态的按钮这个指令会寻找一个ID为action_button、文本是Confirm并且处于启用状态的元素精准度非常高。实操心得利用maestro studio和 App Inspector。当你不确定如何定位一个元素时最好的方法是运行maestro studio录制你的操作它会生成包含定位信息的YAML片段这是最直接的学习方式。使用Xcode的Accessibility Inspector或Android Studio的Layout Inspector来查看UI层级获取元素更详细的属性如content-descAndroid、accessibilityIdentifieriOS这些都可以作为Maestro的定位依据。5.2 调试与日志分析测试失败是常态高效的调试能力是关键。1. 增加详细日志输出运行测试时使用-v(verbose) 标志可以输出更详细的执行日志。maestro test -v my_flow.yaml你会看到Maestro每一步在做什么寻找什么元素等待了多久这对于理解测试卡在哪里至关重要。2. 使用-e参数保留测试后的应用状态默认情况下测试结束后Maestro会清理环境。但调试时你可能希望看到失败那一刻的屏幕状态。maestro test -e my_flow.yaml测试失败后应用不会被关闭你可以手动检查屏幕上的UI。3. 分析Maestro生成的报告Maestro在运行后会生成一个简洁的终端报告显示通过/失败的测试。但更强大的是你可以使用maestro upload命令将结果上传到Maestro Cloud需要注册账号。Maestro Cloud提供了可视化的时间线报告你可以看到每一步的截图、视频回放和日志像看监控录像一样复盘测试执行过程这是定位偶发性问题如竞态条件的神器。4. 处理不稳定元素与智能等待UI自动化最大的敌人是“不稳定”——元素加载有时快有时慢。Maestro内置了智能等待机制在每次交互指令如tapOn,inputText前都会等待目标元素出现默认超时时间。你可以通过defaultTimeout全局配置或为单个指令设置timeout来调整。- tapOn: id: “slowLoadingButton” timeout: 10000 # 为此点击操作单独设置10秒超时此外scrollUntilVisible指令在列表或滚动视图中查找元素时非常有用它会自动滚动直到目标元素出现。5.3 集成到CI/CD流水线自动化测试只有集成到持续集成/持续部署流程中才能发挥最大价值。将Maestro集成到CI/CD如GitHub Actions, Jenkins, GitLab CI中非常直接。一个GitHub Actions工作流的示例 (.github/workflows/maestro-tests.yml)name: Maestro E2E Tests on: [push, pull_request] jobs: test: runs-on: macos-latest # 需要macOS来运行iOS模拟器 steps: - uses: actions/checkoutv3 - name: Setup Java uses: actions/setup-javav3 with: java-version: ‘11’ - name: Install Maestro run: | curl -Ls “https://get.maestro.mobile.dev” | bash echo “$HOME/.maestro/bin” $GITHUB_PATH - name: Start iOS Simulator run: | xcrun simctl boot “iPhone 14” || true - name: Run Maestro Tests run: | maestro test —format junit flows/ test-results.xml env: USERNAME: ${{ secrets.TEST_USERNAME }} PASSWORD: ${{ secrets.TEST_PASSWORD }} - name: Upload Test Results uses: actions/upload-artifactv3 if: always() with: name: maestro-junit-results path: test-results.xml这个工作流做了以下几件事1) 准备macOS环境2) 安装Maestro3) 启动一个iOS模拟器4) 运行所有Flow并生成JUnit报告5) 将报告上传为制品。你可以将JUnit报告与GitHub的代码检查或其他仪表板集成。在CI中的稳定性技巧使用可靠的模拟器/设备镜像在CI中指定一个稳定版本的模拟器避免使用最新的Beta版。测试前清理状态在运行测试前使用maestro stopApp或adb shell am force-stop等命令确保应用是从干净状态启动。处理依赖服务确保你的CI环境能访问测试所需的后端API或Mock服务。设置合理的超时和重试对于整个测试套件在CI配置中设置一个全局超时。对于不稳定的测试可以考虑在Flow级别或通过CI脚本进行有限次数的重试。通过以上五个步骤——从环境搭建、编写第一个Flow、构建复杂逻辑、到高级调试和CI集成——你已经系统地掌握了Maestro移动UI自动化测试的核心技能。这套方法能帮助你快速为项目引入可靠、易维护的端到端测试将团队从繁琐的手工回归测试中解放出来更专注于创造价值。记住所有工具都是为了解决问题而存在Maestro的优势在于它的简洁和高效当你被其他框架的复杂性困扰时它值得你一试。