Key takeaways
- Installation testing on mobile means verifying every path your app can land on a device, not just "install from store." Fresh install, upgrade, restore, sideload, TestFlight, and enterprise builds all behave differently.
- Upgrade path bugs cause more shipped issues than fresh install bugs. A user coming from v2.1 to v4.3 hits code paths that a fresh installer never touches, especially in database migrations.
- The install matrix that catches real production issues is small: 3 paths Γ 2 storage states Γ 2 network states = 12 tests. Run those on real devices, not endless combinations most checklists imply.
Installation testing on mobile is practice of verifying your app installs, launches, and behaves correctly across every path a user can get it onto their device. Fresh install from App Store. Upgrade from an older version. Restore from an iCloud or Google backup. TestFlight beta. Sideload APK. Each is a different code path, and each can break independently.
Most "installation testing" checklists list "install from store" and stop. That's testing 20% of surface. This post covers other 80% with paths iOS and Android actually have and what to test in each.
What installation testing covers
Installation testing verifies four things:
- The app installs on device without errors.
- The app launches for first time and completes initial setup (permissions, terms, onboarding).
- Existing user state carries forward correctly during upgrades and restores.
- The app can be uninstalled cleanly without leaving orphan data.
That's it. Anything beyond that is functional testing pretending to be install testing.
Installation testing is step one, before anything else on this list runs. If install is broken, none of your other test cases matter because user never got past loading screen.
The install paths you actually need to test
Not every user gets your app same way. Here's real set.
iOS install paths:
- App Store production install (public users)
- TestFlight beta (invited testers)
- Ad-hoc distribution (specific UDIDs, up to 100 devices)
- Enterprise distribution (in-house apps, internal companies)
- Xcode direct install (developers on their own devices)
- Restore-from-backup (iCloud or iTunes) - user swapping phones
Android install paths:
- Google Play production install
- Play internal testing track
- Play closed testing (specific email list)
- Play open testing (public beta)
- Sideload APK (direct download or transfer)
- Sideload AAB via bundletool (developer or advanced user)
- Restore-from-backup (Google Drive or manufacturer backup)
- Instant App (Android's run-without-install feature)
That's 6 iOS paths and 8 Android paths. You don't need to test all 14 on every release. You need to know which ones apply to your app and which ones actually differ.
Where they differ:
- Signing certificates. App Store builds are signed with App Store distribution cert. TestFlight builds are signed same way. Ad-hoc uses a different profile. Enterprise uses yet another. Signing bugs can pass one path and fail another. Apple's app distribution guide covers exact entitlement differences per path.
- App attributes and entitlements. App Store builds get certain entitlements automatically. Sideloaded builds might not. If your app uses App Groups, Push Notifications, or Universal Links, sideload might break them.
- Onboarding attribution. A Play Store install with a UTM parameter behaves differently than a sideload with no attribution. Referral flows depend on this.
The IPA is artifact your installation testing run consumes on iOS, and signing state of that IPA determines which install path it can actually take. Similar story for .apk and .aab on Android. Fastlane can automate build-to-device path that feeds every installation testing cycle across App Store, TestFlight, and Play track uploads.
Fresh install vs upgrade vs restore
These three are highest-value scenarios. Skip any and you'll ship bugs.
Fresh install. Device has never seen your app. No stored data. Full permission prompts. Onboarding runs. This is what most people test and it's easiest.
Upgrade install. Existing version replaced by newer one. The user has stored data. Preferences. Cached tokens. Saved cards. Whatever schema your app used, it needs to migrate cleanly to new schema.
This is where Room migrations, Core Data lightweight migrations, and SharedPreferences renames go wrong. v2.1 had a table with a nullable=false column. v2.3 added a new column with nullable=false. If your Migration didn't set a default, existing users crash on first launch after update.
Test upgrade from at least last two public versions. Not three months back. Two versions back.
Restore-from-backup. User bought a new phone. Restored from iCloud or Google backup. Your app appears on home screen, but data behind it is from backup, not from your servers. This is where you find bugs where app assumes it was freshly installed but has stored files from another device.
On iOS, Documents/ gets restored. On Android, files marked for backup get restored. If your session token was in either, user is now on a new device with a valid token that was minted for old device.
The install test matrix that catches bugs
You don't need 300 tests. You need a small matrix that hits real bug surfaces.
Path axis: Fresh install, upgrade from N-1, upgrade from N-2, restore-from-backup. Storage axis: Plenty of storage, low storage (below 500MB free). Network axis: Wi-Fi, cellular only, offline during install completion.
That's 4 paths Γ 2 storage Γ 3 network = 24 test cases. Trim to ones that matter for your app.
A minimum viable set:
- Fresh install on plenty of storage, on Wi-Fi
- Fresh install on low storage, on Wi-Fi
- Upgrade from N-1 with data, on Wi-Fi
- Upgrade from N-2 with data, on Wi-Fi
- Restore-from-backup with cached auth, on Wi-Fi
- Fresh install on cellular with poor signal
Six tests. Real devices only. Repeat on your top iOS and Android devices. Twelve to eighteen runs per release. That catches majority of shipped install bugs.
iOS-specific installation testing gaps
Things iOS has that Android doesn't.
"Delete App" vs "Offload App." iOS lets users offload an app, which keeps user data (documents, Core Data database) but removes binary. When user taps offloaded icon, app re-downloads. Your first launch after re-install with existing data is a code path you probably never tested. Test it.
App Clips. If your app has an App Clip, that's a separate install artifact with its own limits (10MB max, subset of entitlements). Test that App Clip β full app upgrade preserves any user actions taken in Clip.
Restore from backup with Sign in with Apple. SIWA identities are per-Apple-ID. Restoring to a new device with same Apple ID should preserve identity. Restoring to a different Apple ID's device should not. Test both.
Universal Links after install. A user tapped a Universal Link that opened App Store, then installed. Does install remember original link and route them there on first launch? Deferred deep linking. Very few teams test this.
Android-specific installation testing gaps
Android has its own set.
Split APKs (App Bundle). Play Store delivers your .aab as multiple split APKs based on device configuration. The user only downloads what their device needs. This means APK that lands on a Pixel 8 is different from one that lands on a Galaxy S22. Test on both. Split APK bugs are real.
Auto-updates in background. Play Store can update your app while user isn't using it. Existing running Activity might have a different code version than newly installed one. Sounds absurd but happens. Test that app handles version mismatch on next launch.
Auto-restore from backup. Android 12+ enables cloud backup by default for most apps. Your app data gets backed up unless you opt out or configure android:allowBackup="false" explicitly. Users on new devices will restore your app with data. Test with a specific backup, not just any restore.
Google Play install referrer. The Play Store passes install attribution through Install Referrer API. If you're using this for attribution (most consumer apps do), test actual chain: campaign URL β Play Store β install β first launch β your attribution code reads referrer.
The install failures that ship anyway
Six recurring bugs I see across teams that skipped install testing.
Room migration missing. New column added to a table without a Migration class. First launch after upgrade throws IllegalStateException: Room cannot verify data integrity. All existing users crash.
Provisioning profile expired in Enterprise build. Enterprise apps use certificates that expire yearly. When they do, every user's app stops launching. Not a bug you catch in testing unless you specifically watch expiration.
Sign in with Apple identity mismatch after restore. User restored their phone, but SIWA identifier changed subtly (case sensitivity, edge whitespace). Your backend rejects login. User can't get in.
App Group container permissions after enterprise install. Enterprise builds sometimes fail to write to shared app group containers because entitlement path differs from App Store builds. Extensions can't read shared data.
Split APK missing native library on specific device. Your .aab had a native library gated on ARMv8. A user with an older ARMv7 device installed. The library isn't in their APK bundle. First launch crashes with UnsatisfiedLinkError.
Attribution lost on Play Store deferred install. User clicked a campaign link, redirected to Play Store, closed browser, then installed 3 days later. The install referrer window expired. Your attribution shows organic. Marketing budget miscounted.
Where automated install testing fails
Automation of install flows is limited by what your test framework can control.
Selector-based frameworks (Appium, XCUITest, Espresso) can automate app launch and post-install onboarding, but they can't easily automate actual install step. Appium has some support for installing an APK before test start, but doesn't help with upgrade path testing across versions.
For real install testing you often need a wrapper script that:
- Uninstalls current version
- Installs specific old version (v2.1)
- Launches app, walks through onboarding
- Creates known state (user account, cart items)
- Uninstalls without wiping data (Android specifically)
- Installs new version (v2.3)
- Launches app, verifies user is still logged in, cart is preserved
- Tests migrated features work
Every step is a place your test can flake. Steps 3, 4, and 7 depend on interacting with app UI. Selector-based tools fail if any locator changed between versions. Which they usually did. Otherwise you wouldn't be upgrading.
What works for install testing at scale
We built Drizz partly for this shape of problem. Tests are written as plain English commands. Tap "Get started". Type "user@example.com" into "Email". Vision AI reads screen like a person does. When your v2.1 onboarding said "Continue" and your v2.3 says "Next," a Drizz test for step 3 above still works if you tell it to look for what a user would look for.
For upgrade testing specifically, this matters because you're driving different app versions in same test suite. Selector-based tests need per-version test files. Drizz tests describe what user does, not what DOM looks like, so same test can drive an upgrade flow from v2.1 to v2.3.
Concrete before-and-after on "upgrade from v2.1 with cart preserved" test.
Before, on Appium: Test in v2.1 taps com.app:id/get_started_btn. Test in v2.3 needs to tap com.app:id/onboard_primary_cta because ID was renamed. QA lead maintains two test files, or a lookup table of "which ID for which version." Debug time on every version bump.
After, on Drizz: Same test. Tap "Get started" in v2.1. Tap "Continue" in v2.3, written as Tap primary onboarding button and Drizz Vision AI finds it in both cases. One test file, both versions.
For teams shipping every two weeks, this changes install testing from a chore that gets skipped to something that runs on every release.
FAQ
What is installation testing on mobile?
Verifying an app installs, launches, and behaves correctly across fresh install, upgrade, restore, and sideload paths.
What's difference between fresh install and upgrade install testing?
Fresh install starts with no data. Upgrade starts with data from a previous version and must migrate it correctly.
Do I need to test both iOS and Android install paths?
Yes. iOS App Store, TestFlight, and Ad-hoc use different signing. Android Play Store and sideload behave differently too.
What's most common installation bug in mobile apps?
Database migration failures during upgrade. A new column without a proper Migration class crashes every existing user.
How do you test restore-from-backup scenarios?
Install a version, generate user data, back up device, restore to a different device, and verify data integrity.
Can installation testing be automated?
Partially. Install and uninstall commands script easily. UI verification after install needs a reliable test framework.
β


