CI runners need a repeatable way to launch iOS UI tests without opening Xcode. xcodebuild drives the same XCTest runner from Terminal, so a macOS job can build the app, start an iOS Simulator destination, run the UI test bundle, and return a normal process exit code for the pipeline.

A CI command should name the workspace or project, scheme, simulator destination, derived data directory, and result bundle path explicitly. Those values keep the job independent of a developer's local Xcode state and leave the .xcresult bundle in a path the CI system can upload as an artifact.

A workspace named MyApp.xcworkspace, a scheme named MyApp, and an iOS Simulator destination named iPhone 16 keep the placeholders concrete without exposing a real app. Use a macOS runner with full Xcode and a matching simulator runtime; the Command Line Tools package alone does not include the Simulator utilities needed for XCUITest.

Steps to run XCUITest with xcodebuild in CI:

  1. Confirm the CI runner is using full Xcode.
    $ xcodebuild -version
    Xcode 16.4
    Build version 16F6

    If this command reports that the active developer directory is /Library/Developer/CommandLineTools, the runner has only the Command Line Tools package selected and cannot run iOS Simulator UI tests.

  2. List the destinations available to the scheme.
    $ xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -showdestinations
    
    Available destinations for the "MyApp" scheme:
        { platform:iOS Simulator, id:<SIMULATOR-UDID>, OS:18.5, name:iPhone 16 }

    Use -project MyApp.xcodeproj instead of -workspace MyApp.xcworkspace when the scheme belongs to a standalone project.

  3. Remove an old result bundle at the CI artifact path.
    $ rm -rf TestResults/MyAppUITests.xcresult

    Remove only a result bundle path inside the CI workspace. Do not point this cleanup command at shared derived data, source files, or a developer home directory.

  4. Run the XCUITest scheme on the simulator destination.
    $ xcodebuild test \
      -workspace MyApp.xcworkspace \
      -scheme MyApp \
      -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
      -derivedDataPath DerivedData \
      -resultBundlePath TestResults/MyAppUITests.xcresult
    Testing started
    Test Suite 'MyAppUITests.xctest' passed
    ** TEST SUCCEEDED **

    Use build-for-testing in a separate build stage and test-without-building in the test stage only when the CI job preserves the compiled test products, the same DerivedData path, or the generated .xctestrun file.

  5. Check that the result bundle exists before the CI artifact upload step.
    $ ls -ld TestResults/MyAppUITests.xcresult
    drwxr-xr-x  6 ci  staff  192 Jun 26 09:15 TestResults/MyAppUITests.xcresult

    Upload TestResults/MyAppUITests.xcresult as a CI artifact even when the test job fails, so failures still have logs, screenshots, and attachments available for review.