Key checks
Work through the guide
Start with the section that matches your task, then follow the evidence and recovery steps before calling the test complete.
Understand the test-bundle and app-process boundary
Apple distinguishes a simulated location configured for code in a test bundle from the location needed by an application launched as a separate process during UI automation. For the latter, the UI test sets XCUIDevice.shared.location to an XCUILocation. This process boundary explains a common failure: a developer selects a test-plan location, sees the test bundle use it, and assumes the launched app received the same input.
Put the location assignment in the UI-test fixture that owns the scenario. Then launch or navigate in a sequence that makes the product's read point unambiguous. If the app fetches a location only during startup, setting the value after launch is too late. If the feature requests a new fix when a screen appears, document that behavior and wait for its application state rather than relying on an arbitrary delay.
- Use constructed values inside unit tests that call location logic directly.
- Use XCUIDevice location for a separately launched app under UI automation.
- Set the proxy before the code path that requests the relevant location.
- Keep the assignment near the scenario so ownership and cleanup are visible.
Give every UI test an independent fixture lifecycle
A reliable test must pass when run alone, after another test, or in a different order. Define the coordinate, permission state, account, backend fixture, saved place, and launch arguments as one case. Avoid a shared mutable city that one test changes for another. When several tests use the same public coordinate, a helper may construct it, but each test still owns its setup and teardown.
Clear the XCUILocation proxy when the scenario ends so the device can return to the location Core Location otherwise provides. Also remove app-side selections and test-backend overrides. A nil proxy alone cannot erase a cached store, route, or account market. Prove independence by rerunning a neutral-location case after the most stateful test and by randomizing order in a non-release test plan.
- Name fixtures for behavior, such as outsideServiceArea, not only for cities.
- Prefer public test points and avoid customer or employee addresses.
- Reset permissions through an approved test mechanism when the permission branch matters.
- Do not let one test rely on a location or login created by another.
Control permissions, cache, and competing region signals
A mock location value does not grant permission. The app can remain denied, restricted, or limited to reduced accuracy, and the UI must handle each state honestly. Build separate cases for the authorization decisions your product supports. Do not dismiss the system prompt by coordinate tapping in every test; where possible, move authorization handling behind launch-state preparation and reserve end-to-end prompt coverage for a focused suite.
Location is also not the same as IP region, system locale, App Store storefront, saved address, or account country. If a test expects regional content, state which signal owns the decision. A backend request should carry a run identifier or test fixture key so the test can distinguish a valid response from a cached production-like result. This is especially important when a location change triggers asynchronous network work.
- Record authorization and accuracy authorization with the expected screen.
- Make manual-city precedence an explicit product rule.
- Separate device coordinate from IP and account market in assertions.
- Use a test backend or isolated tenant for destructive or stateful flows.
Wait on accessible product state instead of timing guesses
UI automation becomes flaky when a test sleeps and then reads whichever screen happened to finish. Expose an accessibility identifier and meaningful value for the state users rely on: selected branch, availability message, route phase, or permission fallback. Wait for that element or state transition with a bounded timeout, and fail with diagnostics that identify the last accepted timestamp and expected fixture.
Avoid making precise coordinates part of ordinary accessibility labels if users do not need them. A test-only diagnostic surface, launch-gated debug panel, or structured attachment can preserve the low-level evidence without degrading privacy or the production experience. Assert content and control behavior as a user would encounter it, including VoiceOver-friendly labels for any status that is visible in the shipping app.
- Wait for a named state change, not a fixed sleep.
- Assert the final task the user can complete, not only an internal coordinate label.
- Capture a screenshot when visual state helps explain a failure.
- Attach structured diagnostics when cache, backend, or timestamp can be ambiguous.
Keep CI evidence useful and data-minimal
Apple's XCTest attachments can preserve screenshots, strings, files, and other output in test results. Retain what helps reproduce a defect: fixture name, public coordinate or region identifier, authorization state, accepted timestamp, build, backend fixture version, and the failed assertion. Avoid attaching full production responses, personal routes, credentials, or unrelated device logs.
A GPS changer marketing label is not a CI acceptance criterion. The automated contract should remain valid if the input mechanism changes: given an authorized developer location and known environment, the owned app presents the expected state, records the expected test event, and recovers afterward. WLOC can organize coordinate inputs and device-run evidence outside XCUITest, but source-controlled UI automation should keep its deterministic fixture and assertions in the project.
- Set attachment retention deliberately instead of saving everything forever.
- Redact secrets and avoid personal coordinates in CI artifacts.
- Store build and backend fixture versions with the result.
- Review flaky retries as failures of evidence, not proof of eventual correctness.
Decision table
Diagnose an XCUITest location failure by layer
The same unchanged screen can have very different causes, so capture the narrowest evidence that distinguishes them.
| Observed failure | Likely layer | Next assertion |
|---|---|---|
| App uses the physical place | Proxy set after the app's read point | Set before launch and expose accepted timestamp |
| Permission screen blocks progress | Authorization fixture not controlled | Assert status, usage flow, and chosen fallback |
| Old city remains visible | App or account cache | Clear saved selection and verify response run ID |
| Map moves but catalog does not | Backend or competing region signal | Record coordinate, IP, account market, and decision source |
| Test passes only after another test | Shared state or missing teardown | Run alone, clear proxy, and reset fixture ownership |
Practical playbook
Create a location-aware UI test that survives isolation
Use one scenario contract from setup through evidence retention so the test explains both failure and cleanup.
- 1Choose the user outcomeName the screen, control, or workflow that must differ at the authorized test coordinate.
- 2Declare every inputSet the XCUILocation, permission state, account, saved place, backend fixture, and launch arguments for this test.
- 3Assign before the readSet XCUIDevice.shared.location before app launch or before the documented feature request point.
- 4Wait for application stateUse accessibility identifiers and bounded expectations to observe the completed product decision.
- 5Attach narrow evidencePreserve the fixture name, status, timestamp, result, and helpful screenshot without collecting unrelated personal data.
- 6Clear and rerun neutralRemove the proxy and dependent state, then verify an independent neutral case succeeds without test-order assumptions.
References
Verify the claims in this guide
Open the references below for the platform documentation, service policies, and product boundaries used in the guide.
Simulating location in tests
The distinction between test-bundle simulation and XCUILocation for a separately running UI-tested app.
Open the source ↗XCUIDevice location
How a UI test assigns a proxy location and returns to the location Core Location otherwise provides.
Open the source ↗XCUILocation
The proxy type that represents simulated latitude, longitude, and course information.
Open the source ↗Adding attachments to tests
How XCTest retains screenshots, text, files, and other test output for analysis.
Open the source ↗FAQ
XCUITest · UI location automation FAQ
Why does a test-plan location not reach my UI-tested app?
Apple notes that the app under UI automation runs as a separate process. Set XCUIDevice.shared.location to an XCUILocation for that UI test rather than assuming the test bundle's simulated value crosses the process boundary.
When should I set XCUILocation?
Set it before the app or feature requests the location you intend to test. For startup behavior, assign it before launch. Document a later request point if the app refreshes on demand.
Does XCUILocation bypass an iPhone permission decision?
No. Treat authorization and accuracy as independent inputs. The UI test should cover allowed, denied, restricted, and product-supported fallback states separately.
What should a failed location UI test attach?
Keep the fixture name, public test point or region ID, authorization, accepted timestamp, app and backend versions, final assertion, and a useful screenshot. Exclude secrets and personal route data.