Q11 of 26 · Mobile QA
How do you test app behaviour across the full lifecycle — install, background, foreground, and upgrade?
Short answer
Short answer: Appium provides driver.runAppInBackground() to send the app to the background and driver.activateApp() to bring it forward. For install and upgrade scenarios, use ADB (Android) or xcrun simctl (iOS) to install the previous version, seed state, then install the new version and assert data integrity.
Detail
Background/foreground tests verify the app survives OS interruptions — a phone call, switching to another app, the device screen locking. Call driver.runAppInBackground(-1) to background indefinitely, perform the interrupting action, then driver.activateApp('com.example.myapp') to foreground. Assert the app returns to the exact screen the user left, with form state preserved.
Install/upgrade tests are often overlooked and frequently expose database migration bugs. The test flow: (1) install the previous production version via adb install old.apk, (2) launch and create known state (logged-in user, cached preferences, local data), (3) install the new version via adb install -r new.apk (-r replaces without clearing data), (4) launch and assert the migrated state is intact.
Crash recovery: forcibly kill the app (adb shell am force-stop com.example.myapp or driver.terminateApp()), relaunch, and verify the app either restores the last session or starts cleanly — not in a broken half-restored state.
Common findings in lifecycle testing: form data lost on background (not saved to a ViewModel), session tokens cleared on kill (requiring re-login), database corruption after a failed migration, and analytics events fired twice on resume.
// EXAMPLE
lifecycle.test.ts
const APP_ID = 'com.example.myapp';
// Background for 30 seconds, then return
await driver.runAppInBackground(30);
await driver.activateApp(APP_ID);
await expect(screen.checkoutTotal).toHaveText('£49.99');
// Force-stop and cold start
await driver.terminateApp(APP_ID);
await driver.activateApp(APP_ID);
await expect(screen.loginButton).toBeDisplayed();