Automation

Mobile testing with Appium: what changes when the target is an app

People coming from web automation tend to think testing an app is "Selenium with a smaller screen". It isn't. The target stops being a DOM in a browser and becomes a tree of native elements running on an operating system that controls permissions, lifecycle and network — across hundreds of different devices. Appium is the bridge to that world, and understanding what it does under the hood avoids most of the frustration for beginners.

Why an app is a different target

In a web test you have one standard (HTML/DOM) and basically two or three rendering engines. On mobile, each platform has its own UI tree: on Android they are Views exposed by UiAutomator; on iOS they are XCUITest's XCUIElements. These are different automation APIs, maintained by Google and Apple, with their own vocabularies. Add runtime permissions, the app going to the background, screen rotation, the virtual keyboard covering fields and networks that drop — situations that rarely matter in the browser and are everyday life on a phone.

How Appium works under the hood

Appium is a server that speaks the WebDriver protocol (the same as Selenium). Your test sends standardized HTTP commands ("find this element", "tap here") and Appium translates them to the platform's native framework through a driver: UiAutomator2 on Android, XCUITest on iOS. That is the big advantage — you write the test almost the same for both platforms, in any language with a WebDriver client (Java, JavaScript, Python).

  Your test (Java/JS/Python)
        │  WebDriver commands (HTTP/JSON)
        ▼
  ┌──────────────┐
  │ Appium Server│  ── translates ──▶  platform driver
  └──────────────┘
        │                              │
   UiAutomator2 (Android)        XCUITest (iOS)
        │                              │
        ▼                              ▼
     App on device / emulator / simulator

This translation has a cost: each command makes a trip over the network to the device. That's why Appium tests are slower than web tests — and why it's worth keeping the mobile E2E suite lean, pushing as much coverage as possible to cheaper levels, exactly as the test pyramid preaches.

Finding elements: no CSS here

The biggest shock for people coming from the web: there is no CSS selector. You locate by accessibility attributes and by platform-specific strategies. The golden rule is the same as in good locator design — prefer stable identifiers over position or visible text.

StrategyWhen to use
accessibility idFirst choice: stable and cross-platform (maps to contentDescription on Android and accessibilityIdentifier on iOS)
id (resource-id)Good on Android; there's no equivalent on iOS
XPathLast resort: fragile and slow, it walks the entire tree
Ask the dev team for an accessibility id on every testable element. Besides making automation stable, it's the same attribute the screen reader uses — you get testability and accessibility in the same commit.

Gestures, waits and what only exists on mobile

Tapping isn't clicking. Apps live on gestures — swipe, scroll to an element, long press, pinch — which in Appium are expressed through pointer actions (W3C Actions), not a simple click(). And since native UI animates and loads asynchronously, never use a fixed sleep: use explicit waits that wait for the element to become visible or clickable. A fixed sleep is the number one recipe for the flaky tests that haunt mobile suites.

There is also what has no parallel in the browser and needs to be in the test plan:

  • Runtime permissions (camera, location, notifications) — the OS dialog appears on top of the app and has to be handled.
  • Lifecycle: sending the app to the background and bringing it back, and making sure state survives.
  • Network conditions: airplane mode, slow 3G, connection loss in the middle of an action.
  • Interruptions: a call or notification arriving during the flow.

Fragmentation: where you run matters

Writing the test is half the work; the other half is where it runs. Emulators (Android) and simulators (iOS) are fast and great for development, but they don't reproduce real GPU, sensors, camera or the battery and network behavior of a physical device. Real devices catch bugs the emulator hides — at the cost of maintenance and slowness.

And then there is fragmentation: dozens of screen sizes, OS versions and manufacturers that customize Android. Testing on everything is impossible; testing only on your own device is naive. The practical way out is a device matrix based on real data from the people who use the app (the 5–10 most common device+OS pairs in your user base), run on a cloud device farm — BrowserStack, Sauce Labs — to cover the rest on demand.

Conclusion

Testing mobile with Appium reuses what you already know about WebDriver, but the terrain changes: a native tree instead of the DOM, accessibility ids instead of CSS, gestures and explicit waits instead of clicks, and a fragmented ecosystem that forces you to choose where to run with care. Keep the E2E suite lean at the top of the pyramid, attack flakiness with real waits and anchor coverage in a device matrix driven by your real users.

Read also

Back to the blog