Mobile App Testing — iOS & Android Manual & Automation Guide
Mobile app testing presents unique challenges — device fragmentation, OS version differences, network variability, touch interactions, and platform-specific behaviors that do not exist in web testing. In this guide, you will learn manual testing workflows for iOS and Android, automated UI testing with Espresso and XCUITest, strategies for handling device fragmentation, cloud device lab integration, and mobile CI/CD pipelines. DodaZIP's mobile app goes through 200+ device combinations on BrowserStack App Live before every release.
Learning Path
flowchart LR A[Appium Basics] --> B[Mobile Testing Concepts] B --> C[Mobile Manual & Automation
You are here] C --> D[Device Cloud Testing] D --> E[Mobile CI/CD] style C fill:#f90,color:#fff
Mobile Testing Types
| Test Type | What It Covers | Tools |
|---|---|---|
| Functional | Features work correctly | Espresso, XCUITest |
| UI | Visual elements and layout | Robolectric, Snapshot tests |
| Performance | Startup time, memory, battery | Xcode Instruments, Profiler |
| Network | Offline mode, slow networks | Network Link Conditioner |
| Compatibility | Device/OS fragmentation | BrowserStack, Firebase Test Lab |
| Installation | First-run experience | Manual testing |
Android UI Testing with Espresso
// LoginActivityTest.kt
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
@RunWith(AndroidJUnit4::class)
class LoginActivityTest {
@get:Rule
var activityRule = ActivityScenarioRule(LoginActivity::class.java)
@Test
fun testSuccessfulLogin() {
onView(withId(R.id.email_input))
.perform(typeText("user@example.com"))
onView(withId(R.id.password_input))
.perform(typeText("password123"))
onView(withId(R.id.login_button))
.perform(click())
onView(withText("Welcome back!"))
.check(matches(isDisplayed()))
}
@Test
fun testEmptyFieldsShowErrors() {
onView(withId(R.id.login_button))
.perform(click())
onView(withText("Email is required"))
.check(matches(isDisplayed()))
onView(withText("Password is required"))
.check(matches(isDisplayed()))
}
}
iOS UI Testing with XCUITest
// LoginTests.swift
import XCTest
class LoginTests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testSuccessfulLogin() {
let emailField = app.textFields["emailInput"]
emailField.tap()
emailField.typeText("user@example.com")
let passwordField = app.secureTextFields["passwordInput"]
passwordField.tap()
passwordField.typeText("password123")
app.buttons["loginButton"].tap()
let welcomeLabel = app.staticTexts["Welcome back!"]
XCTAssertTrue(welcomeLabel.waitForExistence(timeout: 5))
}
func testInvalidEmailShowsError() {
let emailField = app.textFields["emailInput"]
emailField.tap()
emailField.typeText("invalid")
let passwordField = app.secureTextFields["passwordInput"]
passwordField.tap()
passwordField.typeText("pw")
app.buttons["loginButton"].tap()
let errorLabel = app.staticTexts["Invalid email format"]
XCTAssertTrue(errorLabel.exists)
}
}
Manual Testing Checklist
## Pre-Release Manual Test Checklist
### Installation
- [ ] Fresh install from app store
- [ ] Update from previous version
- [ ] Install on low-storage device
### Network Conditions
- [ ] WiFi connection
- [ ] Cellular (4G/5G)
- [ ] Offline mode
- [ ] Airplane mode
- [ ] Slow network (throttled)
- [ ] Network switching (WiFi to cellular)
### Device Variations
- [ ] Latest iPhone with latest iOS
- [ ] iPhone 2-3 generations old
- [ ] Latest Android flagship
- [ ] Budget Android device
- [ ] Tablet (iPad/Android)
- [ ] Foldable device
### Orientation
- [ ] Portrait
- [ ] Landscape
- [ ] Rotation during active operation
### Interruptions
- [ ] Incoming call during app use
- [ ] SMS received
- [ ] Push notification arrives
- [ ] App switcher
- [ ] Lock/unlock device
Cloud Device Lab Testing
Run tests across hundreds of real devices in the cloud:
import requests
FIREBASE_API = "https://firebase-testlab.googleapis.com/v1"
PROJECT_ID = "my-project"
def run_on_device_matrix():
matrix = {
"testMatrix":
{"androidInstrumentationTest":
{"testApk": {"gcsPath": "gs://my-bucket/app-debug-test.apk"},
"appApk": {"gcsPath": "gs://my-bucket/app-debug.apk"}
}
},
"environmentMatrix":
{"androidDeviceList":
{"androidDevices": [
{"androidModelId": "Pixel3", "androidVersionId": "29"},
{"androidModelId": "Pixel6", "androidVersionId": "33"},
{"androidModelId": "SamsungGalaxyS22", "androidVersionId": "33"},
{"androidModelId": "PixelTablet", "androidVersionId": "34"},
]
}
}
}
r = requests.post(
f"{FIREBASE_API}/projects/{PROJECT_ID}/testMatrices",
json=matrix
)
print(f"Test matrix submitted: {r.json()}")
run_on_device_matrix()
Practice Questions
1. What are the main challenges in mobile app testing compared to web testing?
Device fragmentation, OS version differences, touch interactions, network variability, hardware-specific features, and platform-specific APIs.
2. What is the difference between Espresso and XCUITest?
Espresso is Android's UI testing framework written in Kotlin/Java. XCUITest is Apple's UI testing framework written in Swift. Both automate user interactions and assertions.
3. Why should you test on real devices in addition to emulators?
Emulators cannot reproduce hardware-specific issues — camera quality, battery drain, touch latency, GPS accuracy, and push notification reliability.
4. What is Firebase Test Lab and when should you use it?
Firebase Test Lab runs your Android and iOS tests on hundreds of real device/OS combinations in Google's data centers, ideal for pre-release compatibility testing.
Challenge: Build a mobile test strategy for a file-sharing app. Write Espresso tests for Android (file upload, share dialog, download progress). Write XCUITest equivalents for iOS. Create a manual test checklist covering network conditions, interruptions, and device variations. Set up Firebase Test Lab with a 20-device matrix.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro