How to Write Test Cases for Location Services (With Examples)
How to Write Test Cases for Location Services (With Examples)
How to Write Test Cases for Location Services (With Examples)
Location services are a core capability in many mobile and web applications, powering features such as navigation, geo‑fencing, location‑based recommendations, and emergency‑services integration. Because the underlying hardware (GPS, Wi‑Fi, cellular, or sensor fusion) behaves differently across devices, OS versions, and network conditions, a dedicated test‑case suite is essential to catch defects that generic functional tests miss. This guide walks you through the full lifecycle of creating high‑signal test cases for location services: from understanding the anatomy of a test case, through classification and matrix construction, to data setup, prioritization, automation, and real‑world production edge cases. Each section contains concrete examples, tables, and code snippets you can copy into your test repository today.
1. Understanding Location Services Testing
1.1 What Constitutes a Location Service
A location service is any software component that obtains, processes, or acts upon geographic coordinates. Typical sources include:
- GPS/GNSS – satellite‑based fixes, accurate to a few meters outdoors.
- Wi‑Fi triangulation – uses nearby access‑point MAC addresses and signal strength.
- Cellular tower positioning – relies on signal strength and timing advance from base stations.
- Sensor fusion – combines accelerometer, gyroscope, and magnetometer data for dead‑reckoning when GNSS is unavailable.
- Web Geolocation API – exposes the same sources to JavaScript in browsers, often with user‑permission prompts.
Testing must therefore cover not only the API contract (e.g., latitude/longitude values, accuracy, timestamp) but also the interaction with permission dialogs, background execution limits, and error‑propagation paths.
1.2 Why Dedicated Test Cases Matter
Location‑related bugs often surface only under specific combinations of:
- Signal quality (strong, weak, none)
- Device state (screen on/off, battery saver, airplane mode)
- OS version (different permission models, background‑location limits)
- Network latency (HTTP timeout when reverse‑geocoding)
- User motion (stationary, walking, high‑speed)
A generic test that merely checks “the app shows a map” will miss crashes caused by null latitude values, ANRs triggered by continuous location callbacks, or privacy violations when the app ignores a denied permission. By writing explicit test cases you gain traceability to requirements, enable risk‑based prioritization, and create reusable assets for both manual execution and autonomous exploration platforms.
2. Anatomy of a Location‑Service Test Case
A well‑structured test case makes review, execution, and automation straightforward. The following elements are mandatory for location‑service testing.
2.1 Test‑Case ID and Title
- ID – a unique, sortable identifier (e.g.,
LOC‑001). Prefix with the feature area to aid filtering. - Title – a concise, imperative phrase that states the condition under test (e.g., “Verify app retains last known location when GPS signal drops to zero for 10 seconds”).
2.2 Preconditions
List everything that must be true before the first step runs. For location services this often includes:
- Device location mode set to High accuracy (GPS + Wi‑Fi + cellular).
- Mock location provider enabled (if using emulator or test harness).
- Network connectivity (Wi‑Fi or cellular) unless the test specifically targets offline behavior.
- App launched to a known state (e.g., home screen, login completed).
- Any required permissions already granted or deliberately set to a specific state (granted, denied, never‑asked).
2.3 Test Steps
Numbered actions that the tester or automation script performs. Keep each step atomic and observable. Example steps for a GPS‑loss scenario:
- Enable mock GPS and set initial coordinate to (37.7749, -122.4194) with accuracy 5 m.
- Trigger the feature that starts location updates (e.g., press “Start Tracking” button).
- Wait 5 seconds to confirm steady updates.
- Change mock GPS signal to no fix (return
LocationAvailability: false). - Wait 12 seconds.
- Observe UI and logs.
2.4 Expected Result
A clear, measurable outcome. Avoid vague phrasing like “the app should work”. Instead, state:
- The app displays the last known latitude/longitude within the stored accuracy radius.
- No crash or ANR is recorded in logcat.
- A toast or snackbar informs the user that location is temporarily unavailable.
- Background location service continues to receive updates when signal returns.
2.5 Post‑conditions / Cleanup
Actions that return the device to a neutral state, preventing test bleed‑over:
- Disable mock location provider.
- Reset location mode to device default.
- Clear any cached geofences or stored locations created during the test.
- Close the app or swipe it away from recent‑tasks list.
3. Classification: Positive, Negative, Boundary, and Edge Cases
Organizing test cases by type helps you achieve balanced coverage and prioritize effort.
3.1 Positive Scenarios
These verify that the location service behaves correctly when everything functions as intended.
- Successful acquisition of a fix within a defined timeout.
- Accuracy reported matches the mock provider’s configured value.
- Heading and speed fields update correctly when the simulated device moves.
- Geofence entry/exit events fire at the configured radius.
3.2 Negative Scenarios
These confirm the app handles invalid or missing data gracefully.
- GPS returns
nulllatitude/longitude. - Mock provider supplies coordinates outside the valid range (‑90 > lat > 90, ‑180 > lon > 180).
- Reverse‑geocoding service returns an error code (e.g.,
REQUEST_TIME_OUT). - App lacks the
ACCESS_FINE_LOCATIONpermission and attempts to request updates.
3.3 Boundary and Edge Cases
These push the system to its limits or explore uncommon states.
- Minimum and maximum values for accuracy (0 m and the maximum supported by the device).
- Rapid succession of location updates (e.g., 20 Hz) to stress the main thread.
- Location updates while the device is in Doze mode (Android) or background execution limits (iOS).
- Switching between location modes (GPS only → Battery saving → High accuracy) during an active session.
3.4 Fault‑Injection and Interruption Cases
Simulate real‑world interruptions to verify resilience.
- Airplane mode toggled on/off while location updates are active.
- SIM card removed (cellular‑based positioning lost).
- Wi‑Fi disabled while relying on Wi‑Fi‑only positioning.
- System clock changed abruptly (to test timestamp handling).
- Battery level drops below the threshold that triggers background‑location throttling.
4. Building a Test Matrix: 20+ Example Cases
Below is a concrete test matrix you can import into a test‑management tool. Each row includes an ID, preconditions, numbered steps, and the expected result. Feel free to adjust the values to match your app’s specific APIs.
| ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| LOC‑001 | Device location mode = High accuracy; mock GPS enabled; app at home screen; location permission granted. | 1. Set mock GPS to (40.7128, -74.0060), accuracy 5 m. 2. Tap “Start Tracking”. 3. Wait 8 seconds. 4. Verify latitude/longitude displayed. | App shows latitude ≈ 40.7128, longitude ≈ ‑74.0060 with accuracy ≈ 5 m. No error toast. Location callback count ≥ 3. |
| LOC‑002 | Same as LOC‑001; additionally, network disabled (airplane mode on, Wi‑Fi off). | 1. Set mock GPS to (51.5074, -0.1278), accuracy 10 m. 2. Tap “Start Tracking”. 3. Wait 6 seconds. 4. Attempt reverse‑geocode lookup. | App displays coordinates correctly. Reverse‑geocode shows “Unable to resolve address” or cached value. No crash. |
| LOC‑003 | Device location mode = Battery saving; mock Wi‑Fi provider enabled; app at settings screen. | 1. Add two mock Wi‑Fi APs with known MACs and signal strengths (-60 dBm, -70 dBm). 2. Trigger location request via API. 3. Wait 5 seconds. 4. Read returned location. | Location returned approximates the trilaterated position of the two APs. Accuracy reported between 20‑50 m. No location‑service exception. |
| LOC‑004 | App in foreground; location permission set to Denied; mock GPS enabled. | 1. Attempt to start location updates via button. 2. Observe system dialog. | System shows permission rationale dialog. App does not receive location callbacks. No crash. |
| LOC‑005 | Location permission granted; mock GPS set to return null latitude/longitude. | 1. Tap “Start Tracking”. 2. Wait 10 seconds. 3. Check logs for error handling. | App receives onLocationChanged(null) or equivalent error callback. Displays “Location unavailable” toast. No ANR. |
| LOC‑006 | Device at API level 29 (Android 10); background location limit enabled; app requests foreground location only. | 1. Grant foreground location permission. 2. Start location updates. 3. Press home button to background the app. 4. Wait 30 seconds. 5. Check if location updates continue. | Location updates stop after ~a few seconds (per background limit). App receives onProviderDisabled‑style callback or no further onLocationChanged. No battery drain spike. |
| LOC‑007 | Device API level 33 (Android 13); precise location permission toggle off; approximate location allowed. | 1. Set location to approximate only. 2. Request ACCESS_FINE_LOCATION.3. Attempt to start updates. | System prompts to upgrade to precise location. If user denies, app receives only coarse location (accuracy ≈ 500 m). No crash. |
| LOC‑008 | Mock GPS set to simulate movement at 120 km/h along a straight line; app displays speedometer. | 1. Set initial coordinate (0,0). 2. Start location updates. 3. Increment latitude by 0.001° every 0.5 seconds (approx 111 m/s). 4. Read speed value from UI every second. | Speed displayed approximates 111 m/s (≈ 400 km/h) within 5 % tolerance. No jitter spikes > 20 % due to timestamp handling. |
| LOC‑009 | Geofence registered with radius 50 m around (35.6895, 139.6917); device stationary at center. | 1. Add geofence via API. 2. Wait for dwell transition (default 30 seconds). 3. Simulate exit by moving mock GPS to (35.6905, 139.6927) (≈ 115 m away). 4. Wait 10 seconds. | App receives GEOFENCE_TRANSITION_EXIT event. No premature entry/exit events. Log shows correct timestamp. |
| LOC‑010 | Device in Doze mode (API ≥ 23); app requests location updates with priority PRIORITY_HIGH_ACCURACY. | 1. Enable Doze via adb shell dumpsys deviceidle force-idle.2. Start location updates. 3. Wait 2 minutes. 4. Check if location callbacks still occur. | Location updates are throttled to ~≤ 1 per minute (per Doze behavior). App receives updates at expected low frequency. No crash. |
| LOC‑011 | Mock GPS accuracy set to 0 m (best‑case); app displays accuracy circle on map. | 1. Set mock GPS to any coordinate, accuracy 0 m. 2. Start tracking. 3. Observe map UI. | Accuracy circle radius renders as minimal (often 1‑2 px due to UI scaling). No division‑by‑zero errors. |
| LOC‑012 | Mock GPS accuracy set to maximum supported value (e.g., 2000 m); app shows accuracy indicator. | 1. Set mock GPS accuracy to 2000 m. 2. Start tracking. 3. Verify UI. | Accuracy indicator shows large circle; app does not treat value as invalid. No crash. |
| LOC‑013 | Simulated altitude change: mock GPS provides altitude from 0 m to 2000 m over 30 seconds. | 1. Start location updates. 2. Increment altitude by ~66 m each second. 3. Read altitude value from UI or log. | Altitude updates smoothly, reflecting the simulated change. No clamping at 0 m or 2000 m unless device limits apply. |
| LOC‑014 | Time‑zone shift: device time‑zone set to UTC‑5; app displays local time derived from location timestamp. | 1. Set device time‑zone to America/New_York (UTC‑5). 2. Set mock GPS timestamp to current UTC. 3. Start tracking. 4. Read displayed local time. | Displayed local time equals UTC‑5 conversion of the timestamp. No offset errors. |
| LOC‑015 | Network latency injection: reverse‑geocode API delayed 8 seconds (simulated via proxy). | 1. Enable mock GPS with valid fix. 2. Trigger reverse‑geocode lookup. 3. Introduce 8 s delay on the HTTP response. 4. Observe UI. | App shows loading spinner for ≤ 8 seconds, then displays address or timeout message. No UI freeze; main thread remains responsive. |
| LOC‑016 | Multiple location clients: app A requests high‑accuracy updates; app B requests passive updates. | 1. Install two test apps on same device. 2. Grant both location permissions. 3. Start high‑accuracy updates in App A. 4. Monitor passive callbacks in App B. 5. Verify App B receives updates without extra power drain. | App B receives location updates at same frequency as App A (passive). No additional GPS icon appears for App B. Battery impact ≤ 5 % increase vs. baseline. |
| LOC‑017 | Simulated GPS jump: mock provider returns a position 500 km away after 5 seconds of steady fixes. | 1. Provide steady fixes for 5 seconds. 2. Suddenly jump to distant coordinate. 3. Observe app’s handling (e.g., speed filter, distance‑threshold). | App discards the outlier if speed > threshold (e.g., > 200 m/s) or logs a “GPS jump” warning. Position on map does not teleport; either holds previous position or smooths via filter. No crash. |
| LOC‑018 | Battery‑saver mode enabled; app requests location with PRIORITY_LOW_POWER. | 1. Turn on Battery Saver. 2. Request low‑power location updates. 3. Wait 2 minutes. 4. Check update frequency. | Updates occur at low‑power interval (≥ ~ 1 per minute). GPS icon may appear briefly. App continues to function. |
| LOC‑019 | Simulated NFC‑triggered geofence: tapping an NFC tag writes a latitude/longitude; app reads and creates a geofence. | 1. Tap NFC tag with encoded coordinates (37.7749, -122.4194). 2. App reads tag and adds geofence radius 20 m. 3. Move mock GPS inside radius. 4. Wait for dwell transition. | App receives geofence entry event after dwell time. No delay > 5 seconds beyond expected. |
| LOC‑020 | Permission never‑asked state: app freshly installed, location permission not yet requested. | 1. Launch app. 2. Attempt to start location updates. 3. Observe system permission dialog. | System shows runtime permission rationale. App does not receive location data until user grants. No crash if denied. |
*Feel free to extend this table with additional cases specific to your product (e.g., indoor‑positioning via BLE beacons, barometer‑based altitude, or carrier‑aggregation‑enhanced LTE positioning).*
5. Data Setup and Environment Preparation
Reliable location testing hinges on repeatable control over the inputs that the location subsystem consumes. Below are practical techniques you can apply in both manual and automated contexts.
5.1 Mocking GPS Providers
- Android Emulator – Use
geo fixvia telnet or[ ] adb shell geo fix. For sequences, script a series of fixes withsleepintervals. - iOS Simulator – In Xcode, choose *Debug → Simulate Location* or invoke
xcrun simctl location.set - Third‑party tools – Apps like *Fake GPS Location* (Android) or *Location Spoofer* (iOS, requires jailbreak) let you set coordinates via UI; however, for CI you’ll prefer command‑level control.
- Network‑based mocking – To test Wi‑Fi or cellular positioning, use tools such as *Wi‑Fi‑FoFum* (Android) to broadcast custom beacons, or *Cellular‑Emulator* (open‑source) to fake tower IDs and signal strengths.
5.2 Using Emulators vs. Real Devices
| Aspect | Emulator/Simulator | Physical Device |
|---|---|---|
| Control granularity | High – can inject exact latitude, altitude, speed, satellite count | Limited – you can only spoof via mock location APIs; real RF behavior is opaque |
| Performance | Fast start‑up, no thermal throttling | Real‑world battery, temperature, sensor noise effects |
| OS‑specific quirks | May miss vendor‑specific location‑service bugs | Captures OEM modifications (e.g., Xiaomi’s location‑service power‑saving) |
| Cost | Free (part of SDK) | Requires device lab or cloud‑based device farm |
A robust strategy combines both: use emulators for repeatable functional checks and a rotating set of real devices for regression and performance validation.
5.3 Time‑Zone and Date Handling
Location timestamps are usually expressed in UTC milliseconds since epoch. Tests that depend on local‑time display must:
- Set the device time‑zone explicitly (
adb shell setprop persist.sys.timezone). - Verify that the app converts UTC to local time correctly, applying daylight‑saving rules where relevant.
- Check that the app does not cache time‑zone offsets across reboots (a common bug when the device changes time zones while the app is backgrounded).
5.4 Network Condition Simulation
Reverse‑geocoding, place‑search, and map‑tile downloads rely on HTTP. To emulate adverse conditions:
- Use Android’s Traffic Control (
adb shell tc qdisc add dev wlan0 root netem delay 120ms loss 5%) to add latency and packet loss. - On iOS, employ the *Network Link Conditioner* preference pane.
- In automated scripts, intercept requests with a proxy (e.g., *mitmproxy*) and inject latency or error codes (504, 429).
6. Prioritization and Traceability to Requirements
A test matrix grows quickly; linking each case to a requirement and assigning a priority ensures that limited testing effort focuses on the highest‑impact areas.
6.1 Mapping Test Cases to Functional Requirements
Create a simple traceability table (requirement ID → test‑case IDs). Example:
| Requirement ID | Description | Covered By Test‑Case IDs |
|---|---|---|
| REQ‑LOC‑001 | App shall obtain a location fix within 10 s under good signal. | LOC‑001, LOC‑002, LOC‑008 |
| REQ‑LOC‑002 | App shall handle missing latitude/longitude gracefully. | LOC‑005, LOC‑011, LOC‑012 |
| REQ‑LOC‑003 | App shall trigger geofence entry/exit events with ≤ 5 s latency. | LOC‑009, LOC‑019 |
| REQ‑LOC‑010 | App shall respect background‑location limits on Android 10+. | LOC‑006, LOC‑010 |
| REQ‑LOC‑015 | App shall display accurate speed derived from location updates. | LOC‑008, LOC‑017 |
Having this matrix lets you run a subset (e.g., all cases for REQ‑LOC‑003) when you change geofence logic.
6.2 Risk‑Based Prioritization
Assign a priority based on two factors: impact (user‑visible severity) and likelihood (chance of occurrence in the field). A simple 3×3 grid works:
| Impact \ Likelihood | Low | Medium | High |
|---|---|---|---|
| High (crash, data loss) | P2 | P1 | P0 |
| Medium (incorrect UI, missing feature) | P3 | P2 | P1 |
| Low (cosmetic, rare edge) | P4 | P3 | P2 |
Apply the grid to each test case:
- LOC‑005 (null location) → High impact (possible crash) + Medium likelihood (GPS dropouts) → P1.
- LOC‑012 (maximum accuracy) → Low impact + Low likelihood → P4.
- LOC‑009 (geofence exit) → Medium impact + High likelihood (users move in/out of zones) → P1.
Focus first on P0 and P1 cases; schedule P2‑P4 for each release cycle or nightly runs.
6.3 Coverage Metrics
Track the following quantitative signals to gauge test‑suite health:
- Requirement coverage = (number of requirements with ≥1 test case) / (total requirements) × 100 %
- Priority coverage = (number of P0+P1 cases executed) / (total P0+P1 cases) × 100 %
- Mutation score (if using mutation testing) – proportion of injected faults detected by location‑service tests.
- Flakiness rate – percentage of test cases that produce non‑deterministic outcomes across three consecutive runs; aim for < 2 %.
7. Manual Execution vs. Autonomous Exploration with SUSA
Even the most exhaustive manual test suite can miss scenarios that only appear when real users interact with the app in unpredictable ways. Combining scripted cases with autonomous exploration yields complementary coverage.
7.1 Manual Test‑Case Execution Checklist
Before handing a test case to a human tester, verify:
- Device preparation – location mode, mock provider status, battery level, network condition.
- Prerequisite state – app logged in, any onboarding completed, permissions set as required.
- Step clarity – each action is unambiguous; include expected UI text or log messages.
- Oracles – define how the tester will verify success (visual check, logcat grep, API response).
- Cleanup – steps to reset mock location, disable airplane mode, close the app.
A tester can then follow the checklist, record pass/fail, and attach logs or screenshots.
7.2 How SUSA Augments Location‑Service Testing
SUSA (the autonomous QA platform) can explore an app without any pre‑written scripts, generating real user interactions such as taps, swipes, and system‑dialog handling. When pointed at an APK or a web URL, SUSA:
- Discovers screens that trigger location permissions or start location updates.
- Varies the persona (e.g., “impatient” may rapidly toggle GPS; “elderly” may accept default prompts slowly) to expose timing‑sensitive bugs.
- Detects crashes, ANRs, dead buttons (e.g., a “Locate Me” button that becomes disabled after a permission denial), and accessibility issues (missing labels on location‑related controls).
- Learns from each run: after the first execution it remembers which screens lead to dead ends (e.g., a setting that disables location) and avoids repeating useless paths in subsequent sessions.
While SUSA does not replace deliberately crafted test cases for complex flows (like a multi‑step geofence‑setup wizard), it excels at finding surprise defects that only manifest under particular interaction patterns—such as a background service that fails to restart after the user force‑stops the app from the recent‑tasks list.
7.3 Combining Scripted Cases with Autonomous Sessions
A practical workflow:
- Run the manual/automated test matrix (Sections 4‑6) on every commit. This guarantees coverage of known requirements.
- Trigger a SUSA exploration nightly or before a release candidate. Configure it to:
- Start from the app’s launch activity.
- Allow up to 5 minutes of exploration per session.
- Enable the “adversarial” and “power‑user” personas to stress location‑related UI.
- Collect any new crash logs or ANR traces.
- Triangulate results: If SUSA reports a crash on a screen not covered by your matrix, add a new test case (e.g., “Location permission denied while in the middle of a payment flow”) to the matrix and promote it to P1.
- Feedback loop: Use SUSA’s cross‑session learning to inform future manual test design—e.g., if it repeatedly finds that toggling airplane mode while a geofence is active triggers a toast, incorporate that scenario into your matrix.
This hybrid approach leverages the repeatability of scripted tests and the breadth of autonomous exploration, delivering higher confidence that location services behave correctly in the wild.
8. Automation Strategies: Appium, Playwright, and Custom Scripts
Turning the test matrix into executable checks requires automation frameworks that can control location mocking, assert on UI or API responses, and integrate with CI pipelines.
8.1 Sample Appium Script for Android GPS Mock
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.net.URL;
import java.time.Duration;
public class GpsMockTest {
public static void main(String[] args) throws Exception {
UiAutomator2Options opts = new UiAutomator2Options()
.setAppPackage("com.example.myapp")
.setAppActivity(".MainActivity")
.setAutomationName("UiAutomator2")
.setNoReset(true);
AndroidDriver driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), opts);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
// 1. Enable mock location via ADB (pre‑step, can be done in @Before)
Runtime.getRuntime().exec("adb shell settings put secure mock_location 1");
Runtime.getRuntime().exec("adb shell appops set com.example.myapp android:mock_location allow");
// 2. Send a fixed geo coordinate
driver.executeScript("mobile: geoLocation",
ImmutableMap.of("latitude", 37.7749, "longitude", -122.4194, "accuracy", 5));
// 3. Start tracking in the app
WebElement startBtn = driver.findElement(By.id("btn_start_tracking"));
startBtn.click();
// 4. Wait for location text to appear
WebElement locText = driver.waitUntil(
ExpectedConditions.visibilityOfElementLocated(By.id("tv_location")),
Duration.ofSeconds(8));
String displayed = locText.getText();
assert displayed.contains("37.7749") && displayed.contains("-122.4194")
: "Location not displayed correctly: " + displayed;
// 5. Simulate loss of fix
driver.executeScript("mobile: geoLocation",
ImmutableMap.of("latitude", 0, "longitude", 0, "accuracy", 0, "available", false));
Thread.sleep(12000); // wait for timeout handling
// 6. Verify toast or UI indicator
WebElement toast = driver.findElement(By.xpath("//android.widget.Toast[contains(@text,'unavailable')]"));
assert toast.isDisplayed();
driver.quit();
}
}
Key points:
mobile: geoLocationis an Appium extension that directly feeds coordinates to the fused location provider.- The script toggles mock location via
adbpre‑steps; in a CI environment you can bake these into a device‑setup script. - Assertions are made on UI text and toast presence, providing a clear oracle.
8.2 Sample Playwright Script for Web Geolocation
const { test, expect } = require('@playwright/test
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free