Running iOS tests from the command line shouldn’t require memorizing xcodebuild’s destination strings, SDK flags, and test filtering syntax. This post covers why xcodebuild test is hostile to automation and how FlowDeck replaces it with one command, structured NDJSON output, and live progress.
The typical xcodebuild invocation looks like this:
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=18.4' \
-only-testing:MyAppTests/LoginTests/testValidLogin
Get the destination string wrong and it fails silently. Forget -sdk iphonesimulator and it tries to build for a device you don’t have. The output is hundreds of lines of mixed build logs and test results with no structure. Every guide on this topic, including Apple’s own documentation, shows the same wall of flags from 2020.
There’s a simpler way.
The xcodebuild problem
xcodebuild test works. It’s also hostile to automation.
The destination string is fragile. platform=iOS Simulator,name=iPhone 16,OS=18.4 has to match exactly. If you upgraded Xcode and the OS version changed, the string breaks. If the simulator name doesn’t match, you get a generic “unable to find a destination” error with no suggestion of what’s available.
Filtering tests requires knowing the exact format: TargetName/ClassName/testMethodName. There’s no discovery command. You either know the path or you open Xcode and look.
The output mixes build progress, compiler warnings, test results, and framework logs into one stream. Parsing this in CI means regex. Regex means it breaks when Apple changes the format.
And there’s no progress. Tests run in silence until everything finishes or something crashes.
The FlowDeck way
flowdeck test -S "iPhone 16"
That’s it. FlowDeck resolves the workspace, scheme, and simulator by name. No destination strings. No UDID lookups. No -sdk flag.
Run specific tests
# One test method
flowdeck test --only MyAppTests/LoginTests/testValidLogin
# One test class
flowdeck test --only MyAppTests/LoginTests
# Skip slow tests
flowdeck test --skip MyAppTests/PerformanceTests
Same filtering syntax as xcodebuild, but without the 6 other flags around it.
Discover tests first
flowdeck test discover
Lists every test target, class, and method in your project. FlowDeck uses AST parsing instead of building the entire project, which makes discovery roughly 100x faster than xcodebuild build-for-testing. Useful when you inherit a project and don’t know what’s testable, or when your agent needs to pick which tests to run.
Watch progress
flowdeck test --progress
Shows test results as they complete. Pass, fail, skip. Not 200 lines of silence followed by a summary.
Structured output for CI
flowdeck test --json
Every test result is a typed NDJSON event:
{"type":"test_passed","target":"MyAppTests","class":"LoginTests","method":"testValidLogin","duration":0.42}
{"type":"test_failed","target":"MyAppTests","class":"LoginTests","method":"testExpiredToken","message":"XCTAssertEqual failed: expected 401, got 200","file":"LoginTests.swift","line":87}
{"type":"result","success":false,"passed":14,"failed":1,"skipped":2,"duration":8.3}
No regex. No xcpretty. No xcbeautify. Parse it with jq, pipe it into your CI reporter, or let your AI agent read it directly.
GitHub Actions
- name: Test
run: |
flowdeck test --json | tee test-results.json
# Fail the job if tests failed
tail -1 test-results.json | jq -e '.success == true'
What this is and isn’t
FlowDeck runs your existing XCTest and Swift Testing tests. It calls xcodebuild under the hood. It doesn’t replace your test framework or require any changes to your test code.
It does not generate test coverage reports. Use xcodebuild -enableCodeCoverage YES -resultBundlePath for that. FlowDeck handles the build and execution. Coverage parsing is a separate concern.
Native Swift. Runs locally. No telemetry.
Try it
curl -sSL https://flowdeck.studio/install.sh | sh
flowdeck license activate [YOUR_LICENSE_KEY]
7-day free trial.
Further reading
Ship iOS apps from the terminal.
FlowDeck closes the build-run-test loop for AI agents and humans. One CLI for builds, simulators, logs, UI automation, and more.
$59/yr ·flowdeck license activate · Zero telemetry