Mobile Testing & Appium
In India most people reach the internet through a phone, often a budget Android phone on a busy mobile network. A mobile app has to work on hundreds of screen sizes, several operating system versions and patchy connections, while being interrupted by calls, notifications and low battery. Mobile testing covers all of this, and Appium is the most widely used open-source tool for automating it.
In this lesson you will learn the kinds of mobile apps, where to test them, the mobile-specific test areas, how to choose devices with pairwise testing, and the basics of an Appium test in Python.
Kinds of mobile apps
| Kind | Built with | Example test concerns |
|---|---|---|
| Native | Kotlin/Java (Android), Swift (iOS) | Device features, OS versions, app store rules |
| Hybrid | Web code inside a native shell, or cross-platform frameworks such as Flutter and React Native | Both native and web behaviour, switching between them |
| Mobile web | A website in the phone's browser | Responsive layout, touch, browser differences |
The test approach changes with the kind: a mobile website can be tested with Playwright in a phone-sized browser, while native apps need device automation such as Appium, or the platform tools Espresso (Android) and XCUITest (iOS).
Where to test: emulators, simulators and real devices
- Android emulators (from Android Studio) imitate a whole phone, including the operating system. They are free and fast to reset.
- iOS simulators (from Xcode, on a Mac) imitate the iOS environment but run on the Mac's processor, so performance and some hardware behaviour differ from a real iPhone.
- Real devices show the truth about performance, battery, camera, sensors, touch and the manufacturer's own changes to Android.
- Cloud device farms rent access to many real devices remotely when a team cannot buy them all.
A common approach: develop and run most automated tests on emulators, and run important journeys and release checks on a small set of real devices that match your users.
Mobile-specific test areas
- Interruptions: an incoming call, an SMS with an OTP, a notification, the screen locking, switching apps, the app being killed in the background.
- Network: 4G, slow 2G/3G, Wi-Fi, airplane mode, switching networks in the middle of a payment.
- Device state: low battery and battery saver, low storage, dark mode, large font size, screen rotation.
- Permissions: camera, location, contacts and notifications, including "deny" and "allow only this time".
- Installation and updates: fresh install, update from the previous version with old data, uninstall.
- Gestures: tap, long press, swipe, pinch, and the system back gesture.
- Localisation: Hindi and other Indian languages, long translated text, number and date formats.
- Performance: start-up time, memory use and smoothness on low-end phones.
Choosing devices with pairwise testing
You cannot test every combination of OS version, screen size, network and language. Pairwise testing picks a small set of configurations in which every pair of values appears at least once. Many defects are caused by a single setting or by two settings interacting, so pairs catch a large share of them with far fewer tests. This script builds a pairwise set with a simple greedy method:
from itertools import combinations, product
params = {
"android": ["12", "13", "14", "15"],
"screen": ["small", "medium", "large"],
"network": ["2G/3G", "4G", "Wi-Fi"],
"language": ["English", "Hindi"],
}
names = list(params)
all_combos = list(product(*params.values()))
def pairs_of(combo):
return {((a, combo[a_i]), (b, combo[b_i]))
for (a_i, a), (b_i, b) in combinations(enumerate(names), 2)}
needed = set().union(*(pairs_of(c) for c in all_combos))
chosen = []
while needed:
best = max(all_combos, key=lambda c: len(pairs_of(c) & needed))
chosen.append(best)
needed -= pairs_of(best)
print(f"All combinations: {len(all_combos)}")
print(f"Pairwise set: {len(chosen)} configurations cover every pair of values")
for combo in chosen[:5]:
print(" ", " | ".join(combo))
print(" ...")All combinations: 72 Pairwise set: 12 configurations cover every pair of values 12 | small | 2G/3G | English 12 | medium | 4G | Hindi 13 | small | Wi-Fi | Hindi 13 | large | 4G | English 14 | medium | Wi-Fi | English ...
Twelve configurations instead of 72 still pair every OS version with every network, every screen with every language, and so on. Teams use dedicated tools (such as PICT) for bigger models, and choose actual device models from analytics about their own users.
Appium
Appium is an open-source automation framework for mobile (and some desktop) apps. It uses the same W3C WebDriver protocol as Selenium, so tests look familiar. The current major version is Appium 3. Its architecture:
Your test (Python, Java, JS...) --> Appium server --> driver --> device or emulator
(UiAutomator2 for Android,
XCUITest for iOS)Since Appium 2, the server and the platform drivers are installed separately. Appium needs Node.js (a current LTS release is recommended):
npm install -g appium
appium driver install uiautomator2
appiumThe last command starts the server, which listens on http://127.0.0.1:4723 by default. Install the Python client with python -m pip install Appium-Python-Client. A login test for an Android app looks like this:
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
options = UiAutomator2Options()
options.platform_version = "15"
options.device_name = "Android Emulator"
options.app = "C:/apps/kirana-kart.apk"
driver = webdriver.Remote("http://127.0.0.1:4723", options=options)
try:
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Email").send_keys("priya@example.com")
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Password").send_keys("Kart@2026")
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Log in").click()
greeting = driver.find_element(AppiumBy.ID, "com.kiranakart:id/greeting")
assert greeting.text == "Hello, Priya"
finally:
driver.quit()The options object becomes the session's capabilities, which tell Appium which platform, device and app to use. Printing options.to_capabilities() for these options gives:
{'automationName': 'UIAutomator2', 'platformName': 'Android', 'appium:platformVersion': '15', 'appium:deviceName': 'Android Emulator', 'appium:app': 'C:/apps/kirana-kart.apk'}The accessibility ID locator is the best first choice: it uses the label that screen readers announce, so it is stable across Android and iOS and encourages accessible apps. The same advice about explicit waits, page objects and CI from earlier lessons applies to mobile tests.
Common mistakes
- Testing only on the newest, fastest phone. Many users have older, cheaper devices with less memory.
- Testing only on office Wi-Fi. Throttle the network and try switching networks mid-task.
- Ignoring interruptions. An OTP SMS arriving during checkout is a normal event, not an edge case.
- Fragile locators. Ask developers to add accessibility IDs instead of relying on screen positions or long XPaths.
Key points
- Mobile apps are native, hybrid or mobile web, and each needs a slightly different test approach.
- Emulators and simulators are fast and cheap; real devices reveal true performance and hardware behaviour.
- Mobile-specific areas include interruptions, networks, device state, permissions, updates, gestures and localisation.
- Pairwise testing covers every pair of configuration values with a small number of devices.
- Appium 3 automates mobile apps over the WebDriver protocol, with separately installed drivers such as UiAutomator2 and XCUITest.
Exercise
Add a fifth parameter to the pairwise script, "theme": ["light", "dark"], and run it again. How many full combinations are there now, and how many configurations does the pairwise set need?
Show solution
params = {
"android": ["12", "13", "14", "15"],
"screen": ["small", "medium", "large"],
"network": ["2G/3G", "4G", "Wi-Fi"],
"language": ["English", "Hindi"],
"theme": ["light", "dark"],
}With this dictionary in place of the old one, the first two lines of output are:
All combinations: 144 Pairwise set: 13 configurations cover every pair of values
The full set doubles to 144, but the pairwise set grows only from 12 to 13, because most existing configurations have room to cover the new pairs. This is why pairwise testing scales so well: adding a parameter barely increases the number of tests.
Quick Quiz
1. Which locator is recommended first in Appium?
Accessibility IDs are stable across platforms and also support screen-reader users.
2. Since Appium 2, how are platform drivers such as UiAutomator2 installed?
The Appium server and its drivers are installed and updated independently.
3. What does pairwise testing guarantee?
Pairwise covers all two-way interactions with far fewer configurations.
4. Which is a mobile-specific interruption test?
Calls, SMS, notifications and app switching are everyday mobile interruptions.
Learn Software Testing with a mentor
Free lessons get you started. Our Software Testing training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
