XCUITest: What It Is, How It Works, and iOS UI Testing

Author: IT Sectr Published: 2026-04-09 Reading time: 8 min

XCUITest is an Apple framework for UI testing of iOS, iPadOS, and macOS applications, built directly into XCTest and Xcode. It allows simulating user actions: taps, text input, swipes, scrolling, and gestures — with access to the internal state of interface elements. According to Apple Developer Documentation, 2025, XCUIApplication is the entry point for all UI tests and provides access to the hierarchy of screen elements.

Key Takeaways

  • XCUITest is Apple’s native UI testing framework built into Xcode
  • White-box approach provides access to Accessibility attributes and element hierarchy
  • Tests are written in Swift or Objective-C integrated with XCTest
  • Test recording is available through the built-in recorder in Xcode
  • Execution runs on iOS simulator or a real device without additional servers

What is XCUITest

XCUITest is a UI testing framework released by Apple in Xcode 7 (2015). It replaced UI Automation (UIA) and became the standard tool for automated interface testing on Apple platforms. XCUITest is fully integrated into XCTest — Apple’s unified testing framework.

Difference from XCTest Unit Tests

Unlike unit tests, which verify logic at the class and method level, XCUITest tests the user interface through action simulation. Tests run in a separate process from the application and interact with it through the Accessibility API — this ensures isolation and reliability.

Advantages of the Native Approach

XCUITest does not require installing third-party servers (unlike Appium) or additional libraries for device interaction. Everything needed is already included in Xcode. This ensures the best compatibility with new iOS versions and instant access to new gestures and controls.

XCUITest and XCTest Architecture

The XCUITest architecture is built on two key classes: XCUIApplication — the launched testable application, and XCUIElement — the interface element. The XCTest test runner manages the test lifecycle: setUp, test methods, tearDown. XCUITest runs as a separate process that controls the application through the Accessibility bridge.

Element Hierarchy

Each UI element is represented by an XCUIElement object, which contains methods for querying state (exists, isHittable, label, value) and actions (tap, pressForDuration, swipeUp, typeText). Elements are organized into a hierarchy through Query chains: app.buttons[].staticTexts[].tables[]. This allows flexible finding of any element on the screen.

Accessibility and Locators

XCUITest uses Accessibility attributes to identify elements: accessibilityIdentifier — a programmatic identifier, and accessibilityLabel — a description for VoiceOver. It is recommended to set accessibilityIdentifier in the application code — this makes tests stable regardless of localization and layout.

Writing UI Tests with XCUITest

XCUITest tests are written in Swift using XCTest syntax. Each test class inherits from XCTestCase and contains methods starting with test. In the setUp method, the application is launched with the required configuration, and in tearDown, cleanup and session termination are performed.

Basic Test Scenario

A typical test: find an element → perform an action → verify the result. Element search is done through XCUIElementQuery child queries: app.buttons["loginButton"], app.textFields["email"]. Actions: .tap(), .typeText("text"), .swipeUp(). Assertions: XCTAssertTrue(element.exists) or XCTAssertEqual(element.label, "expected").

swift
import XCTest

class LoginTests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        continueAfterFailure = false
        app.launch()
    }

    func testLoginWithValidCredentials() {
        let emailField = app.textFields["emailInput"]
        emailField.tap()
        emailField.typeText("user@test.com")

        let passwordField = app.secureTextFields["passwordInput"]
        passwordField.tap()
        passwordField.typeText("password123")

        app.buttons["loginButton"].tap()

        let homeLabel = app.staticTexts["homeTitle"]
        XCTAssertTrue(homeLabel.exists)
    }
}

Expectations and Synchronization

XCUITest supports explicit expectations through XCTWaiter and NSPredicate predicates. For example, waiting for an element to appear within 5 seconds: XCTWaiter().wait(for: [expectation], timeout: 5). Unlike Detox, XCUITest does not have automatic synchronization with network requests.

swift
// Waiting for element to appear with timeout
let expectedElement = app.staticTexts["welcomeMessage"]
let existsPredicate = NSPredicate(format: "exists == true")
let expectation = XCTNSNotificationExpectation(object: expectedElement)
let result = XCTWaiter().wait(
    for: [expectation], timeout: 5
)
XCTAssertEqual(result, .completed)

Advanced XCUITest Features

XCUITest supports testing complex scenarios: multi-touch gestures, push notifications, Deep Links, SFSafariViewController, and inter-application interaction. Siri Intents can also be tested through XCUITest using Siri Remote simulation.

Gesture Testing

XCUITest supports all popular gestures: tap, doubleTap, pressForDuration, swipeUp/Down/Left/Right, pinch, rotate, twoFingerTap. For complex scenarios, XCUIGesture is used with custom coordinates and duration. This allows testing custom gestures such as drawing or drag-and-drop.

Network Request Interception

Starting with Xcode 12, XCUITest supports network request interception through XCTestExpectation and URLProtocol. This allows testing the application in offline mode or with mocked server responses without modifying the application code.

XCUITest in CI/CD

XCUITest runs in CI environments through xcodebuild with the test flag. For parallel execution on multiple simulators, xcodebuild -testPlan is used with parallel execution configuration in the Xcode scheme. GitHub Actions, Bitrise, and Jenkins have built-in support for XCUITest.

CI Configuration

For CI, code signing, provisioning profiles, and destination (simulator or device) need to be configured. iOS tests on a simulator do not require certificates. For real devices, automatic signing is required through Xcode Cloud or Fastlane.

bash
# Running XCUITest on simulator via xcodebuild
xcodebuild test \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.5' \
  -resultBundlePath ./TestResults \
  -parallel-testing-enabled YES \
  -parallel-testing-worker-count 4

Testing Accessibility with XCUITest

XCUITest is closely tied to Apple’s Accessibility API, since element search is based on accessibility attributes. Accessibility testing is not only a way to find elements but also a way to verify application accessibility for people with disabilities. XCUITest can check accessibilityLabel, traits, and hints.

VoiceOver Verification

VoiceOver is Apple’s screen reader for visually impaired users. XCUITest allows checking: accessibilityLabel — whether the element is described with clear text, accessibilityTraits — whether the element type matches (button, heading, image), and accessibilityHint — whether it provides a hint about the action result. These checks are mandatory for App Store publication, and XCUITest automates them as part of regression runs.

Automatic Accessibility Check

Starting with Xcode 15, XCUITest supports built-in Accessibility verification through XCTAttachment with the accessibilityAudit type. The test automatically reports elements with insufficient contrast, unlabeled images, and incorrect traits. This replaces the manual Accessibility Inspector.

swift
// Accessibility audit in XCUITest
func testAccessibilityAudit() {
    let app = XCUIApplication()
    app.launch()

    let audit = XCTAttachment(accessibilityAudit: app)
    add(audit)

    // Checking a specific element
    let button = app.buttons["submitButton"]
    XCTAssertTrue(button.label.count > 0)
    XCTAssertTrue(button.isAccessibilityElement)
}

Performance Tests in XCUITest

XCUITest supports UI performance measurement through XCTOSSignpostMetric and XCUIApplication.metrics. You can measure application launch time, navigation speed, and gesture response time. Performance tests run with baseline measurement and automatically fail when the threshold is exceeded. This helps prevent performance regressions before they reach users in a release build.

Baseline Configuration

Baseline is the reference execution time for a test. Xcode remembers the baseline for each test on a specific device model and iOS version. If a new run exceeds the baseline by a specified percentage (default 10%), the test is considered failed. To update the baseline, use the Edit Baseline command in the test report. It is important to recalculate the baseline when updating the iOS version or changing the device model for the CI farm.

Test Stability Monitoring

To monitor XCUITest stability, flags are used: continueAfterFailure (whether to continue the test after the first failure) and Xcode test plans with retry configurations. It is recommended to configure automatic restart of failed tests (retry) — up to 3 attempts for flaky tests related to animation timing or network delays.

Testing Push Notifications and Deep Links

XCUITest supports testing push notifications and Deep Links through springboard and launchArguments. For push notifications, XCUIApplication().launchArguments is used with the -UNUserNotificationCenter parameter and sending through XCTest. Deep Links are tested via open URL with a custom scheme — XCUITest intercepts the system dialog and checks whether the application opened with the correct screen. For testing the notification response scenario, XCUIApplication().springboard is used, which simulates tapping the notification banner in the iOS notification center. These scenarios are critical for applications with deep links and push campaigns, where it is necessary to verify correct handling of external calls.

Integration with Instruments

For detailed performance profiling, XCUITest integrates with Instruments. During the test, profiling of Time Profiler, Core Animation, or Leaks can be launched via XCTMetric. Profiling results are saved in the report and available for analysis in Xcode. This is especially useful for optimizing application launch time, navigation between screens, and animation performance — typical bottlenecks in iOS applications.

Frequently Asked Questions

What is the difference between XCUITest and XCTest?

XCTest is the general framework for all types of Apple tests, including unit tests and performance tests. XCUITest is an extension on top of XCTest for UI testing that adds the XCUIApplication, XCUIElement, and XCUIElementQuery classes for interacting with the interface.

Can XCUITest be used with Objective-C?

Yes, XCUITest supports both Swift and Objective-C. However, most Apple examples and documentation are written in Swift. Objective-C projects can use XCUITest without additional setup — the framework is available through @import XCTest.

How does XCUITest find elements on the screen?

XCUITest uses Apple’s Accessibility API. Elements are found by accessibilityIdentifier, accessibilityLabel, type (button, textField, staticText), or position in the hierarchy. The more precisely Accessibility attributes are set in the application code, the more stable the tests are.

Does XCUITest support test recording?

Yes, Xcode includes a built-in UI test recorder. When running a test in recording mode, Xcode captures all interactions with the interface and generates Swift code. The recorded code can be refined: add assertions, extract into Page Objects, and parameterize.

How to run XCUITest on a real device?

To run on a real device, you need to: connect the device to a Mac, add it to the Apple Developer Program, configure a provisioning profile, sign the application with a development certificate, and select the device as the destination in xcodebuild.

Summary

  • XCUITest is Apple’s native UI testing framework for iOS, iPadOS, and macOS applications
  • Xcode integration provides test recording, parallel execution, and built-in reports
  • XCUIApplication and XCUIElement are the key classes for interacting with the application
  • Accessibility attributes are used as reliable locators, stable during layout changes
  • Expectations are implemented through XCTWaiter and NSPredicate — no automatic synchronization
  • CI/CD is supported through xcodebuild with parallel execution on simulators
  • Advanced scenarios include multi-touch, Siri Intents, network request interception, and Deep Links

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also