Fresh installs, upgrades and data migration
There is a category of mobile bug that only appears at a moment testers rarely recreate: installing and upgrading the app. A fresh install onto a phone that has never had the app, and — trickier — an upgrade from an old version to a new one, carrying over the user's existing data. These paths are skipped because a tester usually already has the current build installed with fresh data. But real users install, and every existing user upgrades, so these paths run millions of times — and a migration bug can wipe or corrupt a user's data (and, for a money app, their balance or transaction history). This lesson is testing installs and upgrades.
Fresh install: the first-run experience
A fresh install is the app arriving on a device that has never had it — no stored data, no cached login, nothing. This is every new user's first experience, and it exercises code the everyday tester (who already has the app set up) never hits:
- First launch and onboarding — does the app start cleanly with no prior data? Do onboarding, tutorials, and initial permission prompts appear correctly (the permissions lesson)?
- Registration / first login — the from-nothing sign-up flow, which a tester with a saved session skips.
- Empty states — no transactions yet, no balance, empty lists. Does the app show sensible "nothing here yet" states, or blank screens / crashes because it assumed data exists?
- Initial data setup — first-run configuration, downloading initial data, creating the local database.
The trap: testers run the app they already have installed and logged into, so they never see the first-run experience the way a new user does. To test it properly you must uninstall completely (clearing all app data and cache) and install fresh — repeatedly. "Clear app data" or a full uninstall-reinstall is how you get back to the true new-user state.
Upgrade: the path every existing user takes
The subtler and more dangerous path is the upgrade — an existing user on an old version installs the new version over it, keeping their data. Every one of your existing users does this on every release, so a bug here hits your whole user base at once. What can go wrong:
- Data migration. The new version may change the local database schema or the format of stored data. On upgrade, the app must migrate the old data to the new format. If migration is missing or wrong, the app can crash on launch (it reads old-format data it no longer understands), lose data (wipes and recreates), or corrupt data (migrates incorrectly). For a money app, losing or corrupting the local transaction history or cached balance on upgrade is a serious bug.
- Stale cached data. Old cached data, tokens, or settings from the previous version may be incompatible with the new code, causing crashes or wrong behaviour until the user clears data (which real users will not know to do).
- Session and login. Does the user stay logged in across the upgrade, or get unexpectedly logged out?
- Feature changes. A setting or feature that moved or was removed — does the old stored preference still make sense?
The critical point: you cannot find upgrade bugs with a fresh install. A fresh install has no old data to migrate, so it sails through — while every existing user hits the migration path. The upgrade bug is invisible to the tester who only ever installs fresh, and visible to every real user on release day.
How to test upgrades properly
Testing the upgrade path requires deliberately recreating it:
- Install the old version first, and use it — create an account, make transactions, generate real stored data in the old format. (Keep old build files, or install the current production version from the store.)
- Then install the new build over it — without clearing data — exactly as a real user's auto-update does.
- Check the migration — does it launch without crashing, is the user still logged in, is their data (balance, transaction history, settings) intact and correct in the new version?
- Test across version jumps — a user might upgrade from two or three versions back (they had auto-update off), not just the immediately previous one. Test the jump from older versions, not only N-1 → N.
- Include it every release — upgrade testing is a per-release regression concern (the regression lesson): every release is an upgrade for existing users, so every release needs the "upgrade from the live version, with real data" check.
This takes deliberate setup (get the old version, populate real data, then update over it) — which is exactly why it gets skipped, and exactly why it is valuable. The QA who does it catches the migration bug in testing; the team that skips it ships a release that crashes on launch or wipes data for every existing user, discovered only when the support tickets flood in.
Why it matters for the target apps
For money-handling apps, install and upgrade correctness is high-stakes:
- Upgrade must never lose or corrupt financial data — a cached balance, pending transactions, or history wiped or wrong on upgrade is a serious defect and a trust-destroyer.
- A crash-on-launch after upgrade locks every existing user out of their money app at once — a critical, whole-user-base incident.
- The empty/first-run states matter because new users are constantly onboarding, and a broken first experience loses them immediately.
So a mobile QA treats "upgrade from the live version with real data" as a mandatory pre-release check, and "fresh install / first run" as a distinct scenario from the everyday already-installed state — because both run at massive scale for real users and both hide bugs the ordinary test session never sees.
Check your work
Fresh install. The from-nothing first experience — first launch/onboarding, registration/first login, empty states, initial data setup — exercising code the already-installed tester never hits. Test it by uninstalling completely / clearing all data and installing fresh.
Upgrade. Installing the new version over an old one with existing data — the path every existing user takes each release. Risks: data migration (missing/wrong → crash-on-launch, data loss, corruption), stale incompatible cache, unexpected logout, changed features. A fresh install cannot find these (no old data to migrate).
Testing upgrades. Install the old version and use it (real data in old format), then install the new build over it without clearing; check it launches, stays logged in, and data (balance/history/settings) is intact; test jumps from several versions back, not just N-1; do it every release.
Why it matters for money apps. Upgrade must never lose/corrupt financial data; crash-on-launch after upgrade locks the whole user base out of their money; broken first-run loses new users. Mandatory pre-release check.
Practice
- Fully uninstall an app and install it fresh; note every first-run screen (onboarding, permissions, empty states) you would otherwise never see.
- Install a prior version of an app, create data (account, some transactions), then update to the new version over it and verify the data survived intact.
- Reason about why an upgrade bug is invisible to a tester who only installs fresh, and visible to every real user.
- Design an upgrade test that jumps from three versions back (a user with auto-update off) to the latest.
- List what could go wrong migrating a local database of transactions on upgrade, and how you would check each.
- Argue why "upgrade from the live version with real data" belongs in every release's regression checklist for a money app.
Official documentation
- Android — Test app upgrades and data migration — Migrating a local database across versions (Room example).
- Android — App startup and first run — First-launch behaviour and cold starts.
- Apple — Testing app updates and data migration — iOS data migration on upgrade.
Next: testing money and transaction flows.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship