Maestro 流動應用程式 UI 測試入門:原理、限制與工具比較
Maestro: Mobile UI Testing Without the Pain - Introduction
Maestro 是支援 Android、iOS 和 Web 應用程式的 UI 及端對端測試框架,讓用戶以 YAML 描述 Flows,並以自動等待和重試減少對固定延遲的依賴。
If you have ever written mobile end-to-end tests, you probably know the routine. You set up Appium, fight with drivers and capabilities, write a test that passes locally, and then watch it fail in CI because an animation took 200ms longer than expected. You add a sleep(2). Then another. Six months later nobody trusts the suite.
Maestro is an open-source framework built to make that experience less painful. This article covers what it is, how it works, what you should know before adopting it, and how it stacks up against the other free and paid options.
This is Part 1 of a two-part series. Part 2 is a hands-on deep dive with a small SwiftUI app and a complete test suite.
What is Maestro?
Maestro is a UI and end-to-end testing framework for Android, iOS and web apps. Instead of writing tests in Java, Kotlin, Swift or JavaScript, you describe user journeys (called Flows) in YAML:
appId: com.example.myapp
---
- launchApp
- tapOn: "Sign in"
- tapOn: "Email"
- inputText: "jane@example.com"
- tapOn: "Password"
- inputText: "hunter2"
- tapOn: "Continue"
- assertVisible: "Welcome, Jane"
That is a complete, runnable test. No page objects, no driver setup code, no explicit waits.
How Maestro works (and why it matters)
Maestro is a black-box tool. It does not link into your app, does not need an SDK, and does not need your source code. It drives the device the way a user would, and it reads the screen through the platform's accessibility layer and view hierarchy.
On iOS, Maestro installs a small XCTest-based driver on the simulator. On Android, it installs a driver app that talks to UIAutomator. The CLI sends commands to the driver, reads back the UI hierarchy, and decides what to do next.
Three design choices make it feel different from older tools:
1. Automatic waiting. After each command, Maestro waits for the screen to settle before moving on. If you tapOn: "Continue" and the button is not visible yet, it keeps looking for a while before failing. In practice this removes most of the sleep() calls you would write elsewhere.
2. Flakiness tolerance. Mobile UIs are noisy: taps sometimes do not register, elements shift during animations, keyboards appear and disappear. Maestro's commands are designed to retry and re-check rather than fail on the first miss.
3. Interpreted, not compiled. Flows are read at runtime. Change a YAML file, rerun, and see the result in seconds. There is no test target to rebuild.
Because it operates "at arm's length", Maestro can also do things in-process tools cannot: tap system permission dialogs, open Safari or Settings, and come back to your app in the same flow.
The ecosystem: CLI, Studio, MCP and Cloud
Maestro is more than one binary. Here is what each piece does and what it costs.
| Component | What it does | Cost | Open source? |
|---|---|---|---|
| Maestro CLI | Runs flows locally and in CI. The core of everything. | Free | Yes (Apache 2.0) |
| Maestro Studio (desktop) | Visual IDE: inspect elements, record interactions, build flows without the terminal. Available for macOS, Windows and Linux. | Free | No |
| Maestro MCP | Built into the CLI (maestro mcp). Lets AI coding agents such as Claude Code, Cursor, Copilot, Codex and Gemini run flows, inspect the screen and write tests. |
Free | Yes |
| Maestro Cloud | Hosted parallel execution on managed simulators, emulators and browsers. | Paid | No |
A note on Studio: older versions of the CLI shipped a browser-based Studio (maestro studio). That was removed in CLI 2.6.0 in favor of the desktop app. If you find older tutorials using maestro studio, that is why they no longer match.
A note on AI: the old maestro chat command was discontinued in 2.7.0. The supported path for AI-assisted test authoring is now Maestro MCP.
Getting started in five minutes
1. Install
You need Java 17 or newer.
java -version
Then install the CLI on macOS, Linux or Windows (WSL):
curl -fsSL "https://get.maestro.mobile.dev" | bash
Or, on macOS with Homebrew:
brew tap mobile-dev-inc/tap
brew install maestro
Verify:
maestro --version
2. Start a device
For iOS you need Xcode with at least one Simulator runtime installed. For Android, an emulator from Android Studio. Maestro can also start one for you:
maestro list-devices
maestro start-device --platform ios
3. Write a flow
Save this as contacts.yaml. It uses the built-in iOS Contacts app, so you do not need your own app yet:
appId: com.apple.MobileAddressBook
---
- launchApp
- tapOn: "Add"
- tapOn: "First name"
- inputText: "Ada"
- tapOn: "Last name"
- inputText: "Lovelace"
- tapOn: "Done"
- assertVisible: "Ada Lovelace"
Button and field labels in Apple's built-in apps can change between iOS versions. If a step fails, open Maestro Studio or run maestro hierarchy to see the exact labels on your simulator.
4. Run it
maestro test contacts.yaml
You will see each step printed as it runs, with a pass or fail marker. On failure, Maestro saves a screenshot, the view hierarchy and logs so you can see what was on screen at the moment it broke.
What is important for developers to know
These are the things that are easy to miss in the marketing material but matter once you adopt Maestro on a real project.
1. iOS testing targets Simulators
Maestro's officially supported local iOS target is the Simulator. You need a Simulator build (.app), not an App Store or Ad Hoc .ipa. Support for physical iPhones has been one of the most requested features in the repository for a long time. Today, if you need real iOS hardware, your options are third-party projects or device clouds that have added Maestro support on physical devices (TestingBot is one example). Check the current docs before you plan around real devices.
Android has no such limitation: emulators and USB-connected physical devices both work.
2. Accessibility identifiers make tests stable
Maestro can find elements by visible text, which is great for getting started. For a test suite you plan to keep, add stable identifiers:
-
SwiftUI / UIKit:
accessibilityIdentifier -
Android:
resource-id/testTag -
React Native:
testID -
Flutter:
Semantics(identifier: ...)or keys exposed through semantics
Then target them with id:
- tapOn:
id: "loginButton"
Text selectors break when copy changes or when you test in another language. IDs do not.
3. YAML is simple until it isn't
For linear user journeys, YAML is a joy. For complex logic (loops with conditions, computed data, calling a backend to seed state), you will reach for Maestro's JavaScript support (runScript, evalScript, ${...} expressions and an http client). It works, but it is not a full programming language with an IDE, types and a debugger. If your test strategy depends on heavy logic, factor that into your choice.
4. Black-box means no app internals
You cannot call into your app's code, stub a network layer from inside the process, or read internal state. If you need that, it has to happen outside Maestro: a test backend, launch arguments, or a debug-only screen. Maestro's own built-in network mocking was deprecated years ago.
5. It is not a replacement for unit or in-process UI tests
Maestro is excellent for high-level user journeys: sign-up, checkout, onboarding, critical paths. It is not the right tool for testing every state of a single component. Keep XCTest/XCUITest, Espresso or your framework's widget tests for that.
6. CI is straightforward, scaling is the hard part
Running Maestro in CI is just maestro test plus JUnit or HTML reports. Scaling is where costs appear. iOS Simulators need macOS machines. Locally you can shard across several simulators (parallel iOS simulator execution became reliable in CLI 2.6.0), but at some point teams either buy more Mac runners or move to a cloud.
7. The project moves fast
The CLI ships frequently, and some releases deprecate flags. For example, --ios-version and --android-api-level are being replaced by --device-os and --device-model. Pin your Maestro version in CI and read the changelog when upgrading.
How Maestro compares to other tools
Free and open-source frameworks
| Tool | Platforms | Test language | Approach | Setup effort | Best for |
|---|---|---|---|---|---|
| Maestro | iOS, Android, Web | YAML (+ JS) | Black-box | Minutes | Cross-platform user journeys, mixed teams, fast feedback |
| Appium | iOS, Android, Web, Windows, more | Java, JS/TS, Python, C#, Ruby | Black-box (WebDriver) | Hours to days | Large cross-platform suites, teams with existing Selenium skills |
| XCUITest | iOS only | Swift / Obj-C | In Xcode, separate test process | Low (built into Xcode) | iOS-only teams who want native tooling and real-device support |
| Espresso | Android only | Kotlin / Java | Gray-box, in-process | Low | Android-only teams, fast and stable component-level UI tests |
| Detox | iOS, Android (React Native) | JS / TS | Gray-box, syncs with RN internals | Moderate to high | React Native apps that need tight synchronization |
| Flutter integration_test / Patrol | iOS, Android (Flutter) | Dart | In-process, Patrol adds native interaction | Moderate | Flutter teams who want tests in Dart |
Maestro vs Appium. Appium is the most flexible and the most mature: any language, any platform, huge ecosystem, real iOS devices. It is also the most work to set up and maintain, and tests tend to need explicit waits. Maestro trades flexibility for speed of authoring and lower flakiness. Many teams that move from Appium to Maestro do so because test maintenance, not test execution, was their bottleneck.
Maestro vs XCUITest. XCUITest is Apple's own framework. It is fast, deeply integrated with Xcode and supports real devices. But tests are Swift code that needs a test target, compilation and more boilerplate, and it only covers iOS. If you ship on both platforms, you would also need Espresso and two separate suites. Maestro gives you one suite, often with shared flows across platforms.
Maestro vs Detox. Detox is gray-box: it knows when React Native is idle, which makes it very stable for RN apps. That same coupling makes setup harder and limits it to React Native. Maestro works with any framework but synchronizes based on what is on screen rather than JS thread state.
Paid platforms and device clouds
Most paid offerings are infrastructure: they run tests you have already written on hosted devices. Prices below are list prices published at the time of writing (October 2026). Always confirm on the vendor's pricing page.
| Service | What you get | Pricing model | Maestro support |
|---|---|---|---|
| Maestro Cloud | Official hosted runner for Maestro flows, parallel execution, artifacts, notifications | $250 per device per month for iOS or Android, $125 per browser per month for web; enterprise plans available; 7-day free trial | Native |
| BrowserStack App Automate | Large real-device cloud for Appium, Espresso, XCUITest and more | Per parallel session; App Automate starts around $199 per parallel per month billed annually | Yes, via integration |
| Sauce Labs | Real devices and emulators, enterprise features | Per parallel test with unlimited users and minutes | Check current docs |
| TestingBot | Real devices and simulators, Maestro CLI integration | Subscription | Yes, including physical iOS devices |
| DeviceCloud (devicecloud.dev) | Maestro-focused cloud runner | Pro plan from $25 per month including test credits, usage on top | Yes |
| AWS Device Farm / Firebase Test Lab | Pay-as-you-go device access from the major clouds | Metered usage with free tiers or trials | Possible with custom setup, not first-class |
| AI-native testing tools (for example Drizz, Autosana) | Natural-language or vision-based test authoring and self-healing | Subscription, usually quote-based | Not applicable; they are alternatives |
A simple way to think about it:
- Authoring cost (how long tests take to write and maintain): Maestro is among the lowest.
- Execution cost (where tests run): free on your own machines, then you pay either for Mac CI runners or for a device cloud. The cloud choice is mostly about price per parallel, device coverage (real vs virtual) and where your data is allowed to go.
When to choose Maestro
Maestro is a strong fit if:
- You ship on both iOS and Android, or plan to.
- You want end-to-end coverage of critical user journeys without building a test framework.
- QA engineers, product people or designers should be able to read and contribute to tests.
- Flaky tests are a bigger problem for you than raw test speed.
Look elsewhere, or combine tools, if:
- You must run iOS tests on physical devices in your own lab with official support.
- Your tests need deep access to app internals or in-process mocking.
- You need thousands of fine-grained UI assertions per component (use XCUITest, Espresso or framework tests for those).
- Your organization already has a large, healthy Appium suite.
Wrapping up
Maestro's pitch is simple: describe what a user does, in plain YAML, and let the framework handle the waiting and retrying. For most teams the biggest win is not execution speed but the fact that tests are quick to write, easy to read and less likely to become the flaky suite nobody trusts.
In Part 2, we will build a small SwiftUI app with a login screen and a to-do list, then write a full Maestro suite for it: stable selectors, sub-flows, environment variables, conditional logic for permission dialogs, tags, reports and a GitHub Actions workflow.
Resources
- GitHub: mobile-dev-inc/maestro
來源:DEV Community · dev.to