Mobile app testing

A complete testing strategy to ensure your application’s quality on any device

10 min

Testing mobile apps is more complex than web: device fragmentation, OS versions, screen sizes, network conditions and system permissions create a combination of variables that makes it impossible to test every scenario manually. A well-designed testing strategy is the only way to maintain quality at scale.

This guide covers everything from unit tests to production crash reporting, including integration tests, automated E2E, device farms and beta testing programmes. The goal is not to test everything but to test what matters systematically and automatically.

The mobile testing pyramid

The testing pyramid remains the most effective model for organising tests. At the base, fast and numerous unit tests that validate isolated business logic. In the middle, integration tests that verify communication between modules. At the top, end-to-end (E2E) tests that simulate complete user flows.

The recommended proportion is roughly 70% unit, 20% integration and 10% E2E. Unit tests run in milliseconds; E2E tests can take minutes. Inverting the pyramid (many E2E, few unit tests) produces suites that are slow, brittle and costly to maintain.

  • Unit (70%): business logic, ViewModels, repositories, utilities
  • Integration (20%): inter-module communication, real APIs with partial mocks
  • E2E (10%): complete user flows on a device or simulator
  • Rule: each level up is slower, more expensive and more fragile

Unit tests in mobile

Unit tests validate isolated code units: functions, classes, ViewModels. On iOS, XCTest is the native framework; on Android, JUnit + Mockito. For Flutter, the test package with mockito. For React Native, Jest is the standard.

The key is to architect the app so business logic is testable without depending on UI frameworks or the OS. Patterns like MVVM, Clean Architecture or BLoC (Flutter) separate logic from presentation, enabling fast tests without starting a simulator.

  • iOS: XCTest + swift-testing (new in Swift 5.9), mocks with protocols
  • Android: JUnit 5 + Mockito/MockK, test doubles with Hilt
  • Flutter: test package + mockito, golden tests for widgets
  • React Native: Jest + React Testing Library for components

Integration tests

Integration tests verify that modules work correctly together: a ViewModel calling a repository that accesses a real or mocked API, or a UI component reacting to state changes. They are slower than unit tests but catch errors that isolated tests miss.

On Android, Instrumented Tests (using AndroidJUnit4) run on an emulator or real device and allow testing components that depend on the Android framework. On iOS, XCTest UI tests launch the real app and simulate interactions. In Flutter, integration_test allows testing widgets with real dependencies.

Automated end-to-end tests

E2E tests simulate real user behaviour: opening the app, navigating, filling forms, making purchases, verifying results. They are the most valuable for detecting regressions in critical flows but also the most expensive to write and maintain.

Maestro is an emerging tool that simplifies E2E test writing with a declarative DSL that works on iOS, Android and React Native. Appium remains the most versatile option for projects needing cross-platform support with a single framework. Detox (by Wix) is optimised for React Native with automatic UI synchronisation.

  • Maestro: declarative DSL, quick to write, supports iOS/Android/React Native
  • Appium: cross-platform, WebDriver-based, large community
  • Detox: optimised for React Native, automatic UI synchronisation
  • XCUITest / Espresso: Apple and Google’s native tools, maximum integration

Device farms and real device testing

Simulators and emulators are useful during development but do not replace testing on real devices. Differences in performance, gestures, sensors and system behaviour between a simulator and a physical device can hide critical bugs.

Cloud device farms allow running automated tests on hundreds of real devices without purchasing them. Firebase Test Lab (free with limits), AWS Device Farm, BrowserStack and Sauce Labs are the most established options. A practical approach is to select 10–15 devices that represent 80% of your user base (according to analytics) and run the E2E suite on them.

  • Firebase Test Lab: CI/CD integration, free tier with 15 tests/day
  • AWS Device Farm: extensive device catalogue, CodePipeline integration
  • BrowserStack: real cloud devices, web and mobile support
  • Device selection: cover the 10–15 models representing 80% of your audience

Beta testing and internal distribution

Before publishing a release, a beta testing programme helps catch issues that automated tests don’t: unexpected usage flows, UI confusion, problems on specific devices or under real network conditions.

TestFlight (Apple) allows distributing betas to up to 10,000 external testers and is the iOS standard. Google Play has closed and open testing tracks. Firebase App Distribution offers cross-platform distribution without going through the stores. The key is having a clear bug reporting process and a structured feedback loop.

  • TestFlight: standard iOS beta distribution, up to 10,000 external testers
  • Google Play testing tracks: internal, closed and open channels with staged rollout
  • Firebase App Distribution: cross-platform, no store submission, Crashlytics integration
  • Structured feedback: in-app bug form, annotated screenshots, automatic logs

Crash reporting and production monitoring

Production crashes are inevitable. What makes the difference is how quickly you detect, diagnose and fix them. A good crash reporting system captures the stack trace, OS version, device model, app state and the steps leading up to the crash.

Firebase Crashlytics is the de facto standard: free, real-time, with intelligent crash grouping and configurable alerts. Sentry offers crash reporting alongside performance monitoring and detailed breadcrumbs. Bugsnag focuses on stability as a business metric with crash-free session dashboards.

  • Firebase Crashlytics: free, real-time, crash grouping, regression alerts
  • Sentry: crashes + performance + breadcrumbs, issue tracker integration
  • Bugsnag: stability score focus, crash-free session dashboards
  • Target: maintain crash-free rate > 99.5% per release

CI/CD for mobile apps

A well-configured CI/CD pipeline runs tests automatically on every pull request, generates staging builds and automates store publishing. This eliminates human error, speeds up the release cycle and ensures every version passes the same quality checks.

Fastlane automates build, signing, screenshot and publishing tasks. GitHub Actions, Bitrise and Codemagic are the most popular mobile CI platforms. A typical pipeline includes: lint, unit tests, integration tests, build, E2E tests on a device farm, beta channel publication and, after validation, production release.

  • Fastlane: automates build, signing, screenshots and publishing on both stores
  • GitHub Actions: free CI for open-source repos, macOS runners for iOS
  • Bitrise: mobile-specialised CI/CD, visual pipeline configuration
  • Codemagic: optimised for Flutter, native iOS and Android support

Key Takeaways

  • The testing pyramid (70% unit, 20% integration, 10% E2E) is the most sustainable model
  • Unit tests require testable architecture: separate logic from presentation
  • Device farms let you test on real devices without purchasing them
  • Beta testing catches problems that automated tests miss
  • Crashlytics or Sentry are essential for detecting production crashes
  • CI/CD with Fastlane eliminates human error and accelerates release cycles

Need a testing strategy for your app?

We design and implement the testing infrastructure that guarantees your application’s quality on every release.