Mobile App Functional Testing: A Detailed Guide

Reading Time : 29 min read
mobile-functional-testing

Mobile app functional testing checks that every feature of your app does what it is supposed to do. Tap the button, get the thing. Fill the form, see the right error. Close the app mid-task, come back, find your work where you left it.

The hard part is not the definition. It is knowing what belongs on your test list, because a phone can break an app in ways a desktop cannot. This guide gives you the list, all fourteen items, nine worked test cases, and a short answer on where each check belongs.

The Short Version

  • Functional testing answers one question: does the feature do what it should.
  • On mobile the list is longer than people expect, because the phone takes part. Interruptions, permissions, offline, backgrounding (what happens when the user switches away from your app and comes back) and deep links are all functional concerns.
  • Start from the 14-item list below and mark what your app does not have yet, rather than building a list from scratch and discovering the gaps in production.
  • Business rules need no device. Anything with a screen or a flow does.
  • Or jump straight to the nine worked test cases.

What is Mobile App Functional Testing?

Mobile app functional testing checks that each feature does what it is supposed to do. Not how fast it runs or how it looks, but whether it works: the button saves the record, the form rejects the bad input, the payment completes and the receipt is right.

Functional testing asks whether a feature does what the requirement says. Non-functional testing asks how well it does it: speed, security, accessibility and ease of use. This guide covers the functional side on mobile. For the broader picture, see our explainer on functional testing. For how visual checks differ, see visual testing vs functional testing.

A functional test is judged against the requirement, not against the implementation. You check the behavior you expect and the failure you expect, and both trace back to something somebody asked for. That holds whether the test is a unit test on one rule or a full flow on a phone.

Why is Mobile App Functional Testing Essential?

A user who cannot log in cannot do anything else. A payment that fails is lost revenue. Functional testing finds those failures before release, when they are cheapest to fix. How the app looks and how fast it runs matter too. Those are non-functional questions and they get tested differently.

How is mobile functional testing different from desktop application testing?

Functional testing for mobile devices puts far more weight on three things than desktop testing does.

The device is not yours. The same build runs on hardware you did not choose, on a version of the OS the manufacturer changed, with a keyboard you did not pick.

The app is not in control. The phone can interrupt it, send it to the background or close it at any moment. The user can revoke a permission in Settings, and your app has to handle the new state when it comes back or relaunches.

The network is not reliable. It drops, switches between Wi-Fi and cellular mid-request, and comes back. Your app gets told, and still has to work out whether the request it was making ever completed.

Each of those turns an ordinary feature into a test case. It is why the list below has rows that look like edge cases and are not.

InterruptionWhat to check
A call or alarm in the middle of a flowThe flow resumes on the same step with the data entered so far
The app goes to the background and the OS closes it to free memoryRelaunch restores state. No duplicate orders or half-saved records
The user switches to another app and comes back ten minutes laterThe session is still valid, or the app asks for sign-in again and returns to the same step
A permission prompt appears mid-flowAllow and Deny both leave the user on a working path
Two pop-ups arrive close together after loginThe app does not depend on them appearing in a fixed order, and neither does your test

Two things catch test suites out. System alerts change with the device language, so a script that taps “Allow” in English stalls on the same alert in Spanish. And pop-ups do not arrive in a fixed order. If a welcome screen shows up two seconds earlier than usual, a script that expects a fixed order leaves it covering the screen, and every step after that fails.

Types of Mobile Functional Testing

Functional testing is usually grouped by how much of the app each check covers, and by what the check is for. For the wider picture beyond functional testing, see our guide to mobile app testing.

  • Unit tests check one function or rule on its own. Fastest and cheapest. Tests that need the platform runtime run on an emulator or a device.
  • Integration tests check that two or more parts work together, usually your app against your API.
  • UI and end to end tests drive the app through its screens the way a user would, a whole flow at a time. Textbooks call these system tests. Most of what this guide covers lives here.
  • Smoke tests are the short set you run on every build to decide whether the build is worth testing at all.
  • Regression tests re-run what already worked, to catch what a change broke.
  • Acceptance tests check the thing against what was actually asked for.

One thing often listed here is not functional testing at all. Usability testing asks whether the feature is easy to use, which is a non-functional question. Exploratory testing is a different case. Point it at whether features do what they should and it is functional testing, which is most of what it gets used for. It is off this list because the list is organized by how much of the app a check covers, and exploratory is how you work rather than how much you cover. Localization testing sits on both sides. Whether the app still works in another locale is functional. Whether the wording reads well is not.

What issues can be detected in mobile apps through functional testing?

Mobile application functional testing catches a specific set of failures. These are the ones that turn up most often.

  • Interface bugs. Buttons, menus, fields and images that cannot be tapped, or that do not respond the way the screen implies they will.
  • Navigation errors. Broken links, a transition to the wrong screen, or a back action that leaves the user somewhere they never came from.
  • Input validation. Input that should be rejected and is not, or that is rejected with a message that does not tell the user what to fix.
  • Wrong behavior. A feature that does the wrong thing rather than nothing. These are the ones that reach production, because nothing crashed.
  • Device-specific failures. A feature that works on one device or OS version and fails on another, such as login on one phone model. Covering the full device matrix is the job of compatibility testing.
  • State and interruption defects. Data lost when the app goes to the background, a draft that disappears, or a form submitted twice after a call interrupts it.
  • Permission and offline failures. A crash or a dead end when the user denies a permission, or a feature that breaks when the network drops and does not recover when it returns.
  • Integration problems. Data that does not survive the trip to another system. The request succeeds, the response parses, and the record on the other side is wrong, duplicated or missing.

What to Test in a Mobile App

Start here. Mark the rows your app does not have yet rather than deleting them, because a deleted row is one nobody tests the day the feature ships. The plans I see are almost never missing effort. They are missing rows, and the missing ones are usually in the bottom half of this list.

What to testWhat you are actually checkingWhat goes wrong
Install, launch and first runA clean install opens, the first-run screens complete, and the app reaches a usable state.The release build fails on an OS version you thought you supported.
Sign up, sign in, sign outEvery route in: new account, returning user, social or SSO, password reset.Reset works but the new password does not, because two screens write to different places.
Session and saved stateAfter backgrounding, device restart or token expiry, the app restores the state it is allowed to restore, and either refreshes the session or asks the user to sign in again. Sign out clears access and account-specific cached data.Sign out leaves cached data on the device for the next user.
Your core task flows, end to endThe three to five things your app exists to do, done the whole way through.Each screen works alone and the flow breaks where two of them meet.
Input validation and error statesEmpty, too long, wrong format, leading spaces, pasted values, and dates, times, currencies and decimals in the device’s own locale format. And what the user is told in each case.The field rejects the input and says nothing useful about why. Or a decimal comma fails validation, because the keyboard produced it and the parser did not expect it.
Navigation and the back stackBack and up from every screen, including after a deep link and after a modal.Back or Up leads somewhere other than the expected destination for the way the user entered the screen.
Rotation, resize and safe areasState and layout survive an orientation change, a split screen, a fold, and the system bars and gesture areas.Locking the app to portrait does not stop a tablet resizing it, and the submit button ends up under the gesture bar.
PermissionsDenial, grant, one-time access where the platform supports it, and revocation in Settings. Return to or relaunch the app and confirm it handles the permission state it actually has.The app assumes permission was granted and crashes or silently does nothing.
Offline and syncWhat the app does with no connection, on a bad connection, and when it comes back.Two edits made offline overwrite each other on reconnect.
InterruptionsA call, an alarm, a notification or a low-battery warning arriving mid-task.The user returns to the start of the flow instead of where they were.
Push notificationsDelivery, the tap-through from closed, backgrounded and foreground states, and the deep destination.The tap opens the home screen instead of the thing the notification was about.
Deep links and app linksLinks from mail, browser, messages and other apps, signed in and signed out.A signed-out deep link loses the destination after login.
Payments and in-app purchasesPurchase, restore, cancel, decline, and what the user owns afterwards.The payment succeeds and the entitlement does not arrive.
Update over an existing installUpgrading from the previous public version with real data already in place.The migration works on a clean install and loses data on a real one.

This list is per feature. The compatibility guide has the shorter list you run per device, once you have a matrix. Accessibility and performance are non-functional, so they are not here, though they do show up on per-device checklists.

Interruptions and offline behavior get treated as edge cases. They are ordinary mobile conditions, and they are where functional bugs hide, because the code path only runs when something interrupts it.

Mark each row for your app. Open Your plan to see where each check belongs.

    No device needed Emulator or simulator Real device

    What We See in the Field

    Login is a good example of why the list above has more rows than people expect. The logic runs the same on an emulator as on a phone. What a real phone adds is everything around it: the manufacturer’s build of the OS, the keyboard, the screen and the biometric hardware.

    From the field In my own app, the same build and the same test passed on three Android phones and failed on a fourth. The failing phone gives the app less screen height than the others. With the keyboard up, the lower fields of one form sat at the keyboard’s edge, and the test’s typing landed in the wrong place. The app’s math was fine. The failure came from keyboard geometry and the way the test entered text. I found it because the suite ran on four different phones and not one. The version of this risk a user would see is a submit button hidden behind the keyboard on a small screen.

    Keyboard covering a form field on a Pixel 8 Pro in a functional test

    Step 1 of the Short form on the failing phone, a Pixel 8 Pro on Android 16. The field under active entry, Amount to Offer Seller, sits at the keyboard’s edge with its input box clipped.

    The opposite case matters as much. Set the minimum OS version higher than your users need and you lock out everyone below it, and no real-device run will tell you, because the devices you reach are newer than the ones that break. An emulator image of an older version catches it in minutes. Install, launch and login on the oldest version you support belongs in the release gate.

    Sometimes the emulator is the better tool. Case 8 below forces an exact API error. The mock that does it works the same on a phone, but the emulator starts from the command line with no device to reserve, so that check can run on every commit.

    A real device is not the whole real world either. On a device cloud, camera input may be an injected image, and a biometric check may be passed or failed from the cloud’s own controls rather than by the sensor. That tells you how your app handles the image, or the pass or the fail, on that device. It does not test the camera, or the phone’s own prompt and sensor. Record injected results separately from native hardware checks.

    How To Perform Mobile Functional Testing

    Functional testing for mobile applications is a loop and not a phase. You decide what matters, write the cases, run each one where it can actually be answered, and read the result properly before you file anything. Here are the steps.

    1. Identify Core Functionalities

    Start with what the app exists to do. For most apps that is three to five flows, and everything else is in service of them. If you cannot name them in a sentence each, that is the first problem to fix.

    2. Plan Functional Test Cases

    Write the cases for those flows first, then work outward. Order them by what breaks worst rather than by what is quickest to write, and give the rows from the list above a place in the plan even when nobody has asked for them.

    3. Set Up Test Environment

    Set up two places to run tests: unit and API tests for business rules, and real devices for anything with a screen or a flow. Reach for an emulator or simulator when something specific stops you using the real thing. Use the list above to find your coverage gaps. The worked cases below show an example environment for each.

    Use the device set from your compatibility plan. If you do not have one yet, see our guide to mobile compatibility testing.

    Shared devices carry the last user’s settings. Before a run, set what your tests depend on, such as language, font size and screen lock, and confirm the installed build is the one you meant to test. A green run on an old build proves nothing.

    4. Develop Automated Test Scripts

    Automate the checks you run most often, starting with smoke and regression. Write them so the same script runs on an emulator and on a real device, then connect them to your continuous integration (CI) pipeline. A common setup runs unit and API tests on every commit, emulator tests on pull requests, real-device tests on merge or overnight, and a short real-device smoke suite as the release gate.

    Keep exploratory testing and brand-new features manual until the flows settle. If you use AI to write or repair tests, review the changed steps and assertions before you trust a pass. Which framework you use matters less here than where you run it. If you are still choosing, our comparison of mobile app testing tools covers the trade-offs.

    5. Execute and Document Test Results

    Run each test in the environment you assigned it and compare the result with the expected result. Record the build, the device or emulator image, the OS version and the outcome, so anyone can reproduce a failure.

    Before you file a failure, confirm it is the app and not the test.

    From the field In my own app, an automated test reported that filling nine new form fields wiped three earlier values. The session’s command log showed every value typed and read back. The video showed the app reaching the next screen with the right numbers. The step that failed was the test’s own lookup afterward, and its error message blamed the form.

    • Read the session before you file. The command log, page source and video show what the app did.
    • Check that the error message names the step that failed and not the step before it.
    • Rerun on the same device and build, and compare the record, not only pass or fail.

    Mobile Functional Test Cases and Where to Run Each

    These nine cases take rows from the list above and work them through in full. Use them as a shape for writing your own.

    Test casePrerequisitesActionsExpected resultWhere to run it
    1. Install, launch and log in on the oldest and newest supported OS versionsThe release build. The oldest and the newest OS version you support. A valid test account.Install the build. Launch the app. Log in.The app installs, opens and reaches the home screen on both versions. No version-block message appears on a supported version.Emulator images to catch a wrong minimum version early. The release build on real devices before you ship.
    2. Biometric login with fallbackBiometrics enrolled on the device. An account with biometric login turned on. The fallback the app is set to offer, and the platform’s documented way to clear a biometric lockout.Run three variations. Success: pass the biometric check. Fallback: fail once and complete whatever the app offers instead. Lockout: keep failing until the platform itself reports lockout, complete the fallback, then clear the lockout the way the platform requires, usually a successful device unlock. If a variation turned biometric login off, turn it back on before the next one.Each variation ends where it should. The fallback appears and works. Lockout is reported by the platform rather than assumed from the fallback appearing. Once the lockout is cleared, a passing check lands on the home screen. The app never loops back to the login screen.A physical device you can reach, with its own biometric sensor, for the native success, failure and lockout checks. On a device cloud the prompt appears but the real sensor is never invoked: you pass or fail the check from the cloud’s own controls, which resolves your app’s callback. That proves your app’s success and failure paths. It does not prove the phone’s own prompt or sensor, so keep those results separate.
    3. Deep link into a signed-in screen, cold startApp installed. User signed out. A valid account. The app’s process ended and confirmed not running, because swiping it away from the recent apps list does not always stop the process. A link to a known protected screen, and a note of which kind it is: a custom scheme, an iOS Universal Link or a verified Android App Link. Those three route differently, so confirm the association for the installed build before you run. The mail app and browser you are testing.Tap the link from the mail app. For the browser variation, tap it from a page on a different domain, because a link from your own domain can legitimately stay in the browser. Log in when asked.The app opens, asks for login, then lands on the linked screen and not on the home screen. A route that is supposed to stay in the browser is a separate test with its own expected result.Real device, with the mail app and browser your users have.
    4. Push notification tap from a closed appApp launched once and registered for push. Notifications allowed. App swiped away from the recent apps list. On Android, do not use Force stop. A visible alert notification, not a silent or background one, that targets a known record. Background delivery is a separate test with a separate expectation.Lock the device. Send the notification. Unlock if the device requires it, then tap the notification.The app launches to the targeted screen with the right record loaded.Real device.
    5. Deny the camera permission, then grant it in SettingsFresh install. A feature that asks for your app’s own camera permission. A system photo picker may never ask for permission, so do not use one here, and on Android do not use a flow that hands capture to another camera app, because that one does not ask either.Start the feature. Deny the permission. Try again. Open Settings, grant the permission, return to the app, then start the feature again.After the denial the app explains what it needs and does not crash. After the grant the feature works when you return or relaunch.Real device, one per platform at minimum.
    6. Interruption during form submitA form with every field filled in, including one value unique to this submission. A way to read the stored records. A way to hold the server response, such as a proxy or a mock delay. A way to trigger a call or an alarm.Tap submit. While the response is held, take the call or let the alarm fire. Release the response. Return to the app. Read the stored records and look for your unique value.Exactly one record is stored, confirmed by reading the records rather than by the success screen. The user sees the result of the submit.Real device, with an alarm, or a call where the device has a working SIM.
    7. Keyboard entry on a small screenThe phone in your set with the least usable screen height. Its default keyboard. A long form.Fill every field from top to bottom with the keyboard up. Submit. Reopen the saved record.Every field and the submit button can be reached. The saved values match what was typed.Real device, and specifically the phone with the least usable screen height.
    8. Validation and error states, forced from the APIA checkout or sign-up form. A way to mock or intercept API responses. A way to see what actually reached the server, so a timeout can be told apart from a silent success.Run three variations: invalid input in each field, valid input with a forced server error, valid input with a forced timeout. Correct the input before you resubmit it, and restore a successful response before you retry a forced error.Invalid input shows a field error. Server errors and timeouts show a clear message and a way to retry. The corrected retry succeeds. After the timeout, check the server: if the first request committed, the retry must not create a second record.Emulator or simulator, because it runs on every commit without reserving a device. The mock works the same on a phone.
    9. An offline edit meets an online edit on the same recordThe same record open at the same revision in the app and in one other place, such as a browser or a second device. One field that both can edit. Offline editing enabled in the app. Your app’s stated rule for which edit wins, and whatever the app is supposed to tell the user when one loses.Take the phone offline and leave the other place online. Change the field to one value in the app and save. Change the same field to a different value in the other place and save. Bring the phone back online and let it sync. Reload the record in both places.Both copies end on the value your stated rule says should win, and the app applies that rule rather than silently picking. If the rule says the user is told when their edit lost, they are told.Real device for the app side, plus whatever runs the second edit.

    Reset permissions, account state, notifications and created records before the next case.

    Read the values back at the end of the flow, not only right after typing them.

    Keep this list short on purpose. Broader release-readiness checks, such as quality gates and sign-off criteria, belong in a release checklist.

    Best Practices for Mobile Functional Testing

    A few habits do more work than the rest in functional testing for mobile apps. These are the ones worth building into how the team runs, rather than remembering to do.

    Test the Network Response

    Test the app on a bad network and not only a slow one. Drop the connection mid request, switch between Wi-Fi and cellular while a call is in flight, and come back after a timeout. What you are looking for is whether the app recovers on its own or sits there until the user restarts it.

    Run Each Check Where It Can Actually Be Answered

    Real devices are not the answer to everything, and business rules are where they are wasted. Price math, validation logic and parsing are faster and more reliable as unit tests, and that layer should be the biggest one you have.

    Anything with a screen or a flow needs a device, because that is the only place you find out how it behaves on one. There is one real exception worth knowing. Tools like Robolectric run Android UI tests on the JVM with no device involved, and they prove your UI logic holds. What they do not tell you is how the screen behaves on a phone.

    Once a check needs a device, a real one is the default. Emulators and simulators are what you reach for when something specific stops you: you do not have the device, you need an OS version no handset ships yet, you need to force a state a real phone will not give you, or you need the scale and speed of running on every commit.

    Most of those are reasons of access, cost and speed. The exception is an OS version or a device state no phone in your rack will give you. Forcing an exact API error is not an exception: the mock does that work, and it works the same on a phone. Case 8 uses an emulator or simulator because it runs on every commit without reserving a device.

    Both platform owners put the release gate on real hardware. Apple says simulators “don’t replicate the performance or features of a physical device” and tells you to verify on physical devices. Google opens with “Always test your Android app on a real device before releasing it to users.” Apple also recommends simulators for hardware you do not have, which is the same trade this section describes.

    The checks that depend on the phone and not on your code are the ones worth protecting: permissions, interruptions, the real apps that own a link, the manufacturer’s battery management, payments against a live store account, and anything touching the camera, biometrics or sensors. You can fire a push or open a deep link on an emulator, and an Android emulator can even run real Chrome and Gmail. What it cannot give you is the manufacturer’s own build of the OS and its battery manager, which decide whether the notification arrives at all.

    Test in Different Languages

    Switch the device language and run your core flows again. Longer strings push buttons off the screen, and a translated error message can lose the part that told the user what to fix. Right to left layouts break navigation in ways a translation review never catches, because nothing is wrong with the words. Language is also not the only locale setting that changes behavior. Date, time, currency and decimal formats change what your parsing sees, so switch the locale and not only the language.

    Role of Mobile Functional Testing in Agile and DevOps

    Functional tests earn their keep when the pipeline runs them rather than when someone remembers to. Configure your CI/CD pipeline to run the fast checks on every commit, so a regression is found by the build and not by a person a week later. The same test finds the same bug either way. Only one of those is cheap to fix.

    Run the device tests in parallel. That is what makes a wider device matrix affordable, because the time a run takes stops rising with every model you add. Step 4 above has a cadence to start from. The gate matters more than the cadence. Decide which suite has to be green before a build ships, and put that one on real devices.

    Next Steps

    Start from the list above, mark what your app does not have yet, and check what is left.

    Kobiton runs manual and automated tests on real iOS and Android devices. What that gives you:

    • Real iOS and Android devices, with the manufacturer’s build of the OS, the keyboards and the screens your users actually have, and devices with a working SIM for the call, SMS and OTP flows that need one
    • Appium scripts generated from your manual sessions
    • Session Explorer, so you can read what actually happened before you file a bug: the command log, session video and step screenshots, device logs, and the device’s own metrics such as CPU, memory, network, battery and temperature, alongside an accessibility scan. Turn on network payload capture and you also get the API requests and responses with a HAR file

    Start a no-commitment free trial.

    Start a free Kobiton trial on real devices

    Mobile Functional Testing FAQ

    What is included in mobile functional testing?

    Every feature doing what it is supposed to do, which on mobile is a longer list than people expect. Install, launch and first run; sign up, sign in and sign out; session and saved state; your core flows; input validation and error states; navigation and the back stack; rotation, resize and safe areas; permissions; offline and sync; interruptions; push notifications; deep links and app links; payments; and updating over an existing install. That is the full fourteen. Add the features and account states your own app has on top of them.

    What is the difference between functional and non-functional testing on mobile?

    Functional testing asks whether the feature works. Non-functional asks how well it works: how fast, how reliably, how easy to use, how secure. Battery drain and app start time are non-functional. Whether the payment completes is functional. The two overlap in practice, because a flow that is slow enough starts failing for timing reasons that look functional.

    How is mobile functional testing different from testing a desktop app?

    The phone takes part. Interruptions arrive while the app is running, permissions can change mid-session, and the network comes and goes. Desktop software meets all three too. The difference is that on mobile they are the normal case rather than the exception.

    Do functional tests need a real device?

    Business rules do not need a device, and that layer should be large. Anything with a screen or a flow does, and a real device is the default. Emulators and simulators are for when something specific stops you, and the section above has the full list of reasons.

    Interested in Learning More?

    Subscribe today to stay informed and get regular updates from Kobiton

    Ready to accelerate delivery of
    your mobile apps?

    Request a Demo