🎁 Free starter workshopHaving a SW issue?
Back to blog
Guides & TutorialsTestingMobile AppsQAGuide

How to Test Mobile Apps Properly

Lukáš HusoApril 28, 202610 min read
How to Test Mobile Apps Properly
Photo: Daniel Romero / Unsplash

Mobile apps are tested differently than web apps. On the web, you essentially have two rendering engines (Chromium and WebKit), predictable screen sizes, and stable network connections. On mobile, you have thousands of different devices, dozens of OS versions, unreliable networks, and users who will interrupt your app with a phone call at the worst possible moment. A solid testing strategy is therefore a necessity, not a luxury.

The testing pyramid for mobile apps

The testing pyramid concept applies to mobile development too, but with important nuances. The base consists of unit tests, the middle of integration tests, and the tip of end-to-end tests. The ratio should be roughly 70:20:10.

Unit tests verify isolated units of code -- functions, classes, utilities. In mobile development, you typically test business logic, data transformations, form validations, and state management. The tools depend on the platform: Jest for React Native, XCTest for Swift, JUnit for Kotlin.

Unit tests should be fast (the entire suite under 30 seconds), deterministic (no dependencies on network or real databases), and should cover edge cases. If your code processes dates, test midnight transitions, leap years, and daylight saving time changes. If it processes amounts, test negative values, zero, and maximum values.

Integration tests verify that components work together correctly. You typically test API communication (with a mocked server), data persistence (writing to and reading from a local database), navigation between screens, and proper component interaction.

For integration tests in React Native, React Native Testing Library has proven effective -- it tests components from the user's perspective, finding elements by text and accessibility labels rather than internal structure. For native iOS and Android, XCUITest and Espresso serve this purpose.

End-to-end tests simulate complete user journeys from launching the app to achieving a goal. Registration, login, performing the main action, logout. These tests are the slowest and most fragile, so keep them to a minimum -- cover critical business flows and happy paths.

Unit tests (70%)

Isolated testing of functions, classes, and business logic. Fast, deterministic, covering edge cases. Tools: Jest, XCTest, JUnit.

Integration tests (20%)

Verifying component collaboration -- API communication, data persistence, navigation. Tools: React Native Testing Library, Espresso, XCUITest.

E2E tests (10%)

Complete user journeys from launch to goal. Slowest layer, cover only critical flows. Tools: Detox, Maestro, Appium.

Beta testing and UAT

Real-world testing with users via TestFlight / Firebase App Distribution. Clear feedback structure, 1-2 week duration.

Device fragmentation -- the main challenge of mobile testing

The Android ecosystem comprises thousands of different devices from dozens of manufacturers. Each manufacturer customizes the system in their own way -- Samsung has One UI, Xiaomi has MIUI, Huawei has EMUI. These skins can affect app behavior in ways you won't catch in an emulator.

Screen resolutions and sizes. From 4-inch compact phones to 7-inch phablets and foldable devices. Your UI must work on all of them. Test on at least four categories: small phone (iPhone SE / Galaxy A-series), regular phone (iPhone 15 / Pixel 8), large phone (iPhone 15 Pro Max / Galaxy S24 Ultra), and tablet.

Operating system versions. On iOS, the situation is simpler -- most users update relatively quickly and supporting the last 2-3 versions is sufficient. On Android, the situation is dramatically worse. Android 12 and older are still used by a significant percentage of users, especially on budget devices. Before deciding which versions to support, check data from Google Play Console or Firebase Analytics for your specific market.

Performance on lower-end devices. Your app might run beautifully on a Pixel 8 Pro with 12 GB of RAM. But how does it perform on a Samsung Galaxy A14 with 3 GB of RAM and a slower processor? A significant portion of your users will use it on exactly these devices. Test animation smoothness, loading times, and memory consumption on a device from a lower price range.

Real devices versus emulators

Emulators and simulators are invaluable for rapid development and basic testing. But they have limits you need to be aware of.

Where emulators suffice: Unit tests, integration tests, basic UI layout testing, testing different resolutions and OS versions, automated CI/CD tests.

Where you need real devices: Performance and animation smoothness testing (emulators have different performance characteristics), hardware feature testing (camera, GPS, biometrics, NFC), push notification testing under real conditions, behavior testing on specific manufacturers (Samsung, Xiaomi), network behavior testing (Wi-Fi to cellular handoff, weak signal).

The ideal approach is to have 3-5 real devices for manual testing (covering different manufacturers, sizes, and price ranges) and use cloud device farms for automated tests across a broader spectrum. Firebase Test Lab, BrowserStack, and AWS Device Farm offer access to hundreds of real devices on demand.

Tools for automated testing

Choosing the right tool for E2E testing of mobile apps is crucial, because a wrong choice will cause more frustration than benefit.

Detox is a framework from Wix designed specifically for React Native. Its biggest advantage is synchronization -- Detox knows when the app has finished animations and network requests, making tests significantly more stable than competitors. The downside is that it only works with React Native.

Maestro is a relatively new tool that has quickly gained popularity due to its simplicity. Tests are written in YAML -- you don't need to know any programming language. It's platform-agnostic (works with native and cross-platform apps) and has excellent developer experience. For most teams, Maestro is the best choice today to start with E2E testing.

Appium is the oldest and most widespread framework. It supports virtually any mobile platform and any programming language. The price for this flexibility is complex configuration and slower test execution. Appium makes sense for large teams with a dedicated QA department and the need to test across many platforms.

CI/CD for mobile apps

Continuous Integration for mobile development has its specifics compared to web development.

Build pipeline. Every push to the main branch should trigger: linting and static analysis, unit tests, integration tests, and building the app for both platforms. An iOS build requires a macOS runner (GitHub Actions offers macOS runners, but they are more expensive). An Android build can run on Linux.

Automated E2E tests. Run them at least once daily or before each merge to the main branch. They are too slow and expensive to run on every commit. Use parallelization -- iOS and Android tests can run simultaneously.

Automatic distribution. After tests pass successfully, the build should automatically be distributed to testers. This brings us to beta testing.

Beta testing and distribution

Before publicly releasing your app, you need to test it with real users under real conditions.

TestFlight for iOS is the standard path. Apple provides it for free, supports up to 10,000 external testers, and allows gradual rollout. Builds go through a basic Apple review (faster than a full review), so expect a 24-48 hour delay.

Firebase App Distribution (formerly Crashlytics Beta) works for both Android and iOS. Distribution is immediate (no review process), you can create tester groups, and track who has installed the build. For Android, it's a simpler alternative to Google Play internal testing.

Google Play internal testing and closed testing tracks allow you to distribute the app through Google Play, but only to selected testers. The advantage is that testers receive updates the same way as final users.

The key to beta testing is having a clear feedback structure. Give testers a form or a dedicated channel for reporting issues. Ask about specific scenarios, not just "how do you like it." And set a timeframe -- the beta phase should last 1-2 weeks, not months.

Crash monitoring in production

Even the best testing won't catch every problem. In production, you need monitoring that tells you about issues before your users do.

Sentry and Firebase Crashlytics are the two most widely used crash reporting tools. Both capture unhandled exceptions, provide stack traces, device information, and user steps leading to the crash. Crashlytics is free and deeply integrated with the Firebase ecosystem. Sentry offers more configuration and works beyond mobile apps.

Set up alerting on crash-free rate. If the percentage of sessions without crashes drops below 99.5%, you should know immediately. Both Apple and Google use crash-free rate as one of the factors for store visibility.

Beyond crashes, monitor ANR (Application Not Responding) on Android and hang rate on iOS. These issues are often more frustrating for users than crashes because the app appears frozen and users don't know whether to wait or close it.

Start test automation with the highest ROI: unit tests for business logic and a few E2E tests for critical paths (registration, login, main action). Deploy crash monitoring from day one in production. Add more sophisticated layers (integration tests, device farms, performance monitoring) gradually over time.

What to test -- a practical checklist

Beyond the obvious functional tests, there are scenarios specific to mobile apps that are frequently overlooked.

Interruptions. An incoming phone call while filling out a form. A push notification from another app. Switching to another app and back. Locking and unlocking the phone. Your app must survive these interruptions without losing data.

Network conditions. Slow connection (3G), network loss mid-request, transitioning from Wi-Fi to cellular data. Test with network throttling -- both the Android emulator and Xcode simulator can simulate various network conditions.

Offline mode. What happens when a user opens the app without internet? Do they see cached data? A clear error message? A blank screen? If your app supports offline mode, test data synchronization after connectivity is restored, including conflicts (user changed data offline while it also changed on the server).

Memory management. On Android, the system can kill your app in the background if it needs memory for another app. Upon return, the app should restore to its last state. Test this scenario -- Android Studio has a "Terminate application" option to simulate this behavior.

Different languages and localization. German translations are longer than English ones, Arabic reads right to left, Japanese has no spaces between words. If you're localizing your app, test the UI with all languages -- a button that looks great with the text "Save" might overflow with "Speichern."

Conclusion

Testing a mobile app is more complex than testing a web app, but it doesn't have to be insurmountably difficult. Start with the basics -- solid unit tests for business logic, a few key E2E tests for critical paths, and crash monitoring from day one in production. Gradually add more sophisticated layers: integration tests, automated testing on real devices, performance monitoring.

The most important thing is to start. An imperfect testing strategy that exists is infinitely better than a perfect strategy you plan to implement "next time." Every bug caught before release is a bug your user will never see -- and that is an investment that always pays off.

Get your custom price

Our configurator shows you an indicative price for your project in 2 minutes.

Related Articles

How to Create a Mobile App: The Complete Guide from Idea to App Store
Guides & TutorialsGuideMobile Apps

How to Create a Mobile App: The Complete Guide from Idea to App Store

Step by step, how to create a mobile app — idea validation, MVP, specification, technology choice, development, publishing and operations. Including what you can do yourself for free.

July 5, 202610 min read
An App Without Testing: Everything That Can Go Wrong

An App Without Testing: Everything That Can Go Wrong

Real stories about apps that shipped without proper testing. From wrong prices to leaked private messages and vanishing money.

March 26, 20266 min read
The two biggest challenges of AI development: quality assurance and big-model dependency

The two biggest challenges of AI development: quality assurance and big-model dependency

Code generation is nearly free now — the bottleneck is QA and human judgment. And the second challenge: when production really needs a large LLM, and when deterministic code or a small local model does the job.

July 7, 20267 min read