QA Testing (iOS)
Use xcodebuild + Xcode Simulator (simctl) to build, run, and stabilize iOS tests.
Primary docs: XCTest, Swift Testing, simctl, Xcode testing
Inputs to Confirm
- Xcode entrypoint:
-workspace or -project
-scheme (and optional -testPlan)
- Destination(s): simulator name + iOS runtime (or
OS=latest), and whether real devices are required
- UI-test hooks: launch arguments/env toggles (stubs, demo data, auth bypass, disable animations)
- Artifact needs:
xcresult, coverage, screenshots/video, logs
Quick Commands
| Task |
Command |
| List schemes |
xcodebuild -list -workspace MyApp.xcworkspace |
| List simulators |
xcrun simctl list devices |
| List devices (USB) |
xcrun xctrace list devices |
| Boot simulator |
xcrun simctl boot "iPhone 15 Pro" |
| Wait for boot |
xcrun simctl bootstatus booted -b |
| Build app |
xcodebuild build -scheme MyApp -sdk iphonesimulator |
| Install app |
xcrun simctl install booted app.app |
| Run tests |
xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=latest' -resultBundlePath TestResults.xcresult |
| Run tests (device) |
xcodebuild test -scheme MyApp -destination 'platform=iOS,id=<UDID>' -resultBundlePath TestResults.xcresult |
| Reset simulators |
xcrun simctl shutdown all && xcrun simctl erase all |
| Take screenshot |
xcrun simctl io booted screenshot screenshot.png |
| Record video |
xcrun simctl io booted recordVideo recording.mov |
Workflow
- Resolve build inputs (
workspace/project, scheme, testPlan, destinations).
- Make simulator state repeatable: shutdown/erase as needed, boot, and wait for boot.
- Run tests with artifacts enabled (
-resultBundlePath); parallelize and retry only when appropriate.
- Triage failures from the
xcresult bundle; confirm flakes with repetition; quarantine with an owner and reproduction steps.
xcodebuild Patterns
- Select tests to reproduce:
-only-testing:TargetTests/ClassName/testMethod and -skip-testing:TargetTests/FlakyClass.
- Prefer test plans for large suites:
-testPlan <plan> (keeps device/config/runs consistent).
- Enable parallel testing when suites are isolation-safe:
-parallel-testing-enabled YES (+ -maximum-parallel-testing-workers N).
- Always write a result bundle in automation:
-resultBundlePath TestResults.xcresult.
- For reruns, split build and test:
xcodebuild build-for-testing ... then xcodebuild test-without-building ....
- Inspect results locally:
open TestResults.xcresult or xcrun xcresulttool get --path TestResults.xcresult --format json.
Flake Triage (Repetition and Retry)
- Prefer repetition to prove flake rate before adding retries.
- Use targeted reruns before suite-wide retries.
Common patterns (flags vary by Xcode version):
- Retry failing tests once in CI:
-retry-tests-on-failure -test-iterations 2
- Measure flakiness until first failure:
-test-iterations 50 -test-repetition-mode until-failure
- Run a single test repeatedly:
-only-testing:TargetTests/ClassName/testMethod -test-iterations 20
Testing Layers
| Layer |
Framework |
Scope |
| Unit |
XCTest / Swift Testing |
Business logic (fast) |
| Snapshot |
XCTest + snapshot libs |
View rendering |
| Integration |
XCTest |
Persistence, networking |
| UI |
XCUITest |
Critical user journeys |
Device Matrix
- Default: simulators for PR gates; real devices for release
- Cover: one small phone, one large phone, iPad if supported
- Add OS versions only for multiple major release support
Flake Control
Use these defaults unless the project requires otherwise:
- Disable or reduce animations in UI-test builds.
- Fix locale/timezone (via launch arguments or app-level configuration).
- Stub network at the boundary (avoid real third-party calls in UI tests).
- Reset app state between tests (fresh install, deep-link reset, or explicit teardown).
- Prefer state-based waits (
waitForExistence, expectations) over sleeps.
- Pre-grant/reset permissions where possible (simulators):
xcrun simctl privacy booted grant ....
CI Integration (GitHub Actions)
name: iOS CI
on: [push, pull_request]
jobs:
test:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "16.0"
- run: |
set -euo pipefail
xcodebuild test \
-scheme MyApp \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=latest' \
-resultBundlePath TestResults.xcresult
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: TestResults.xcresult
Do / Avoid
Do
- Make UI tests independent and idempotent
- Use test data builders and dedicated test accounts
- Collect
xcresult bundles on failure
- Use accessibilityIdentifier, not labels
Avoid
- Relying on test ordering or global state
- UI tests requiring real network
- Thread.sleep() for synchronization
- Accepting AI-proposed selectors without validation
Resources
| Resource |
Purpose |
| references/swift-testing.md |
Swift Testing framework |
| references/simulator-commands.md |
Complete simctl reference |
| references/xctest-patterns.md |
XCTest/XCUITest patterns |
Templates
| Template |
Purpose |
| assets/template-ios-ui-test-stability-checklist.md |
Stability checklist |
Related Skills
1---2name: qa-testing-ios3description: Run and stabilize iOS tests (XCTest, XCUITest, Swift Testing) on simulators and devices with xcodebuild/simctl: choose destinations, manage simulator state, control flakes (locale/time/network/animations), configure CI, and collect/parse xcresult artifacts.4---5
6# QA Testing (iOS)
7
8Use `xcodebuild` + Xcode Simulator (`simctl`) to build, run, and stabilize iOS tests.
9
10**Primary docs**: [XCTest](https://developer.apple.com/documentation/xctest), [Swift Testing](https://developer.apple.com/documentation/testing), [simctl](https://developer.apple.com/documentation/xcode/simctl), [Xcode testing](https://developer.apple.com/documentation/xcode/testing-your-apps-in-xcode)
11
12## Inputs to Confirm
13
14- Xcode entrypoint: `-workspace` or `-project`
15- `-scheme` (and optional `-testPlan`)
16- Destination(s): simulator name + iOS runtime (or `OS=latest`), and whether real devices are required
17- UI-test hooks: launch arguments/env toggles (stubs, demo data, auth bypass, disable animations)
18- Artifact needs: `xcresult`, coverage, screenshots/video, logs
19
20## Quick Commands
21
22| Task | Command |
23|------|---------|
24| List schemes | `xcodebuild -list -workspace MyApp.xcworkspace` |
25| List simulators | `xcrun simctl list devices` |
26| List devices (USB) | `xcrun xctrace list devices` |
27| Boot simulator | `xcrun simctl boot "iPhone 15 Pro"` |
28| Wait for boot | `xcrun simctl bootstatus booted -b` |
29| Build app | `xcodebuild build -scheme MyApp -sdk iphonesimulator` |
30| Install app | `xcrun simctl install booted app.app` |
31| Run tests | `xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=latest' -resultBundlePath TestResults.xcresult` |
32| Run tests (device) | `xcodebuild test -scheme MyApp -destination 'platform=iOS,id=<UDID>' -resultBundlePath TestResults.xcresult` |
33| Reset simulators | `xcrun simctl shutdown all && xcrun simctl erase all` |
34| Take screenshot | `xcrun simctl io booted screenshot screenshot.png` |
35| Record video | `xcrun simctl io booted recordVideo recording.mov` |
36
37## Workflow
38
391. Resolve build inputs (`workspace/project`, `scheme`, `testPlan`, destinations).
402. Make simulator state repeatable: shutdown/erase as needed, boot, and wait for boot.
413. Run tests with artifacts enabled (`-resultBundlePath`); parallelize and retry only when appropriate.
424. Triage failures from the `xcresult` bundle; confirm flakes with repetition; quarantine with an owner and reproduction steps.
43
44## xcodebuild Patterns
45
46- Select tests to reproduce: `-only-testing:TargetTests/ClassName/testMethod` and `-skip-testing:TargetTests/FlakyClass`.
47- Prefer test plans for large suites: `-testPlan <plan>` (keeps device/config/runs consistent).
48- Enable parallel testing when suites are isolation-safe: `-parallel-testing-enabled YES` (+ `-maximum-parallel-testing-workers N`).
49- Always write a result bundle in automation: `-resultBundlePath TestResults.xcresult`.
50- For reruns, split build and test: `xcodebuild build-for-testing ...` then `xcodebuild test-without-building ...`.
51- Inspect results locally: `open TestResults.xcresult` or `xcrun xcresulttool get --path TestResults.xcresult --format json`.
52
53### Flake Triage (Repetition and Retry)
54
55- Prefer repetition to prove flake rate before adding retries.
56- Use targeted reruns before suite-wide retries.
57
58Common patterns (flags vary by Xcode version):
59
60- Retry failing tests once in CI: `-retry-tests-on-failure -test-iterations 2`
61- Measure flakiness until first failure: `-test-iterations 50 -test-repetition-mode until-failure`
62- Run a single test repeatedly: `-only-testing:TargetTests/ClassName/testMethod -test-iterations 20`
63
64## Testing Layers
65
66| Layer | Framework | Scope |
67|-------|-----------|-------|
68| Unit | XCTest / Swift Testing | Business logic (fast) |
69| Snapshot | XCTest + snapshot libs | View rendering |
70| Integration | XCTest | Persistence, networking |
71| UI | XCUITest | Critical user journeys |
72
73### Device Matrix
74
75- Default: simulators for PR gates; real devices for release
76- Cover: one small phone, one large phone, iPad if supported
77- Add OS versions only for multiple major release support
78
79### Flake Control
80
81Use these defaults unless the project requires otherwise:
82
83- Disable or reduce animations in UI-test builds.
84- Fix locale/timezone (via launch arguments or app-level configuration).
85- Stub network at the boundary (avoid real third-party calls in UI tests).
86- Reset app state between tests (fresh install, deep-link reset, or explicit teardown).
87- Prefer state-based waits (`waitForExistence`, expectations) over sleeps.
88- Pre-grant/reset permissions where possible (simulators): `xcrun simctl privacy booted grant ...`.
89
90## CI Integration (GitHub Actions)
91
92```yaml
93name: iOS CI
94on: [push, pull_request]
95jobs:
96 test:
97 runs-on: macos-15
98 steps:
99 - uses: actions/checkout@v4
100 - uses: maxim-lobanov/setup-xcode@v1
101 with:
102 xcode-version: "16.0"
103 - run: |
104 set -euo pipefail
105 xcodebuild test \
106 -scheme MyApp \
107 -sdk iphonesimulator \
108 -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=latest' \
109 -resultBundlePath TestResults.xcresult
110 - uses: actions/upload-artifact@v4
111 if: always()
112 with:
113 name: test-results
114 path: TestResults.xcresult
115```
116
117## Do / Avoid
118
119### Do
120
121- Make UI tests independent and idempotent
122- Use test data builders and dedicated test accounts
123- Collect `xcresult` bundles on failure
124- Use accessibilityIdentifier, not labels
125
126### Avoid
127
128- Relying on test ordering or global state
129- UI tests requiring real network
130- Thread.sleep() for synchronization
131- Accepting AI-proposed selectors without validation
132
133## Resources
134
135| Resource | Purpose |
136|----------|---------|
137| [references/swift-testing.md](references/swift-testing.md) | Swift Testing framework |
138| [references/simulator-commands.md](references/simulator-commands.md) | Complete simctl reference |
139| [references/xctest-patterns.md](references/xctest-patterns.md) | XCTest/XCUITest patterns |
140
141## Templates
142
143| Template | Purpose |
144|----------|---------|
145| [assets/template-ios-ui-test-stability-checklist.md](assets/template-ios-ui-test-stability-checklist.md) | Stability checklist |
146
147## Related Skills
148
149| Skill | Purpose |
150|-------|---------|
151| [software-mobile](../software-mobile/SKILL.md) | iOS development |
152| [qa-testing-strategy](../qa-testing-strategy/SKILL.md) | Test strategy |
153| [qa-testing-mobile](../qa-testing-mobile/SKILL.md) | Cross-platform mobile |