Skip to content

Mobile Testing

Mobile testing verifies apps that run on devices you do not control: different OS versions, screen sizes, network conditions and hardware. It splits into two families that cover different kinds of behaviour.

unit / widget → fast, on-host: logic, view models, composables
UI / E2E → a real device or emulator exercising the full app

UI tests further split by reach: a white-box test (Espresso, XCUITest) runs inside the app process and can see internals, while a black-box test (Appium, Maestro) drives the app the way a user does. Real-device clouds (Firebase Test Lab, BrowserStack App Automate) fill the gaps in your local device matrix.

Use it for

  • Critical journeys on each platform: onboarding, login, checkout, permissions
  • Platform-specific behaviour: notifications, deep links, biometrics, rotation
  • Verifying release builds on a representative device and OS matrix
  • Flows that depend on device capabilities (camera, GPS, offline mode)

Avoid it when

  • The behaviour is pure logic that a faster unit or widget test can cover
  • You are testing the same journey exhaustively on every device — sample the matrix instead
  • A shared cross-platform flow is already covered on one platform and the code is common
  • You need web-only checks — that is cross-browser
Tool Ecosystem Notes
Appium Multi (Android, iOS, web) WebDriver protocol, cross-platform, black-box
Espresso Android (Kotlin/Java) Fast white-box UI tests in-process
XCUITest iOS (Swift/Obj-C) Apple’s native UI testing framework
Detox React Native Gray-box, auto-synchronises with the app
Maestro Multi (Android, iOS, web) YAML flows, low-flake, easy onboarding
Firebase Test Lab Android, iOS Real and virtual devices in the cloud
BrowserStack App Automate Multi Real device cloud for Appium/Espresso/XCUITest
Terminal window
npm install -g appium
appium driver install uiautomator2
appium driver install xcuitest
appium
it('logs in on Android', async () => {
await $('~email').setValue('ada@example.com');
await $('~password').setValue('s3cret');
await $('~login').click();
await expect($('~dashboard')).toBeDisplayed();
});
  • Prefer accessibility IDs. Coordinates and screen positions break on the next device.
  • Wait for state, not the clock. Use framework synchronization and explicit waits over fixed sleeps.
  • Sample the device matrix. Cover OS extremes, one low-end device and one large screen, not every model.
  • Reset app state per test. Fresh install or deep clean avoids order-dependent flakiness.
  • Run the slow device suite on a cloud and keep fast unit and widget tests local.
  • Test the release build too. Debug-only behaviour and ProGuard/R8 stripping can break shipped apps.

Self-assessment quiz

Pick one answer per question, then press Check answers.

  1. What distinguishes a white-box mobile test from a black-box one?
  2. Which is the native UI testing framework for iOS?
  3. Which tool uses YAML flows and aims for low-flake onboarding?
  4. Why prefer accessibility IDs over screen coordinates?
  5. What does a real-device cloud such as Firebase Test Lab provide?