XCTestRunner¶
✅ Implemented 🧪 Tested 📱 Simulator Only
Current state:
XCTestRunneris a fully implemented Swift package (ios/XCTestRunner/) withAutoMobileTestCase,AutoMobilePlanExecutor,AutoMobileTestObserver,TestTimingCache, andAutoMobileSession. Plans execute against a booted iOS Simulator via the AutoMobile daemon over a Unix domain socket. Published as a local SPM package; remote GitHub release in progress. See the Status Glossary for chip definitions.
The AutoMobile XCTestRunner lets you write host-side XCTest classes that drive a real iOS Simulator
over the AutoMobile daemon. Tests execute as ordinary unit tests inside a dedicated test target, so
they run with xcodebuild test-without-building with no separate UI test runner process required.
How it works¶
sequenceDiagram
participant X as xcodebuild test-without-building
participant T as AutoMobileTestCase (XCTest)
participant E as AutoMobilePlanExecutor
participant D as AutoMobile Daemon
participant S as iOS Simulator
X->>T: run test method
T->>E: setUpWithError → makeConfiguration
T->>E: executePlan()
E->>D: connect via Unix socket
E->>D: executePlan(YAML content)
D->>S: launchApp / observe / tapOn / …
S-->>D: UI state + screenshots
D-->>E: success / failedStep
E-->>T: ExecutePlanResult
T-->>X: PASS or FAIL
Each test class points to a YAML plan file bundled with the test target. The executor encodes the plan and sends it to the AutoMobile daemon over a Unix domain socket. The daemon drives the simulator step by step and returns a structured result. No separate UI test process or XCUITest runner binary is involved.
Why not XCUITest directly?¶
| AutoMobile XCTestRunner | XCUITest | |
|---|---|---|
| Runs as | Unit test target | UI test target (separate process) |
| Build required | Pre-built .xctestrun reused |
Full UI test host recompile |
| Device needed at | Test execution only | Build time (linking) + execution |
| Parallel devices | Daemon-managed pool | One device per test bundle |
| AI recovery | Optional self-healing | Not available |
| Test authoring | YAML plans or AI prompt | Swift/Objective-C code |
| App under test | Any installed app | App compiled into UI test host |
Requirements¶
- macOS 13.0+ (Ventura or newer)
- Xcode 15.0+ and Command Line Tools
- A booted iOS Simulator
- AutoMobile daemon running (
auto-mobile --daemon start) - CtrlProxy iOS installed in the simulator (see CtrlProxy iOS)
Quick start¶
1. Add the dependency¶
# ios/YourApp/project.yml (XcodeGen)
packages:
XCTestRunner:
path: ../../libs/spm/XCTestRunner
# ios/YourApp/project.yml (XcodeGen)
packages:
XCTestRunner:
url: https://github.com/kaeawc/auto-mobile
from: "0.0.14"
// Package.swift
.package(url: "https://github.com/kaeawc/auto-mobile", from: "0.0.14")
See Project Setup → Dependency for the full XcodeGen target configuration and instructions for committing a local copy for CI reproducibility.
2. Write a test¶
// YourApp/Tests/AutoMobile/AppLaunchAutoMobileTests.swift
import XCTest
import XCTestRunner
final class AppLaunchAutoMobileTests: AutoMobileTestCase {
override var planPath: String {
"test-plans/launch-app.yaml"
}
override var cleanupOptions: AutoMobilePlanExecutor.CleanupOptions? {
AutoMobilePlanExecutor.CleanupOptions(
appId: "com.example.ios.YourApp",
clearAppData: true
)
}
override func setUpAutoMobile() throws {
let daemonReady = DaemonManager.ensureDaemonRunning()
guard daemonReady else {
throw XCTSkip("AutoMobile daemon is not running and could not be started")
}
}
func testAppLaunchesWithoutCrashing() throws {
let result = try executePlan()
XCTAssertTrue(result.success, "Plan failed: \(result.error ?? "unknown error")")
XCTAssertGreaterThan(result.executedSteps, 0)
}
}
3. Write the plan¶
# YourApp/Tests/AutoMobile/test-plans/launch-app.yaml
name: launch-app
description: Launch the app and verify it opens without crashing
platform: ios
steps:
- tool: launchApp
appId: com.example.ios.YourApp
clearAppData: true
label: Launch the app with a clean state
- tool: observe
label: Verify the app UI renders without crashing
- tool: terminateApp
appId: com.example.ios.YourApp
label: Terminate the app after test
4. Run¶
# Start the daemon (if not already running)
auto-mobile --daemon start &
# Build for testing
xcodebuild build-for-testing \
-scheme YourApp \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-derivedDataPath build/DerivedData
# Run only the AutoMobile test bundle
xcodebuild test-without-building \
-xctestrun build/DerivedData/Build/Products/*.xctestrun \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:YourAppAutoMobileTests
See Project Setup → Running tests locally for the full step-by-step walkthrough.
Pages in this section¶
| Page | What it covers |
|---|---|
| Project Setup | SPM dependency, XcodeGen config, test target setup, running locally |
| Writing Tests | AutoMobileTestCase properties, YAML plan reference, examples |
| CI Integration | GitHub Actions, build-for-testing artifact, daemon setup |
Related¶
- CtrlProxy iOS — Required for view hierarchy access and gesture injection
- MCP Tools reference — Full list of tools available in YAML plans
- simctl integration — Simulator lifecycle management