iOS Automation Testing with Xcode UI Framework

โšก Smart Summary

iOS automation testing with Xcode records and replays user interface actions against an application under test, following a test-driven cycle of design, test, implement and test again until every case passes.

  • ๐Ÿ”˜ TDD cycle: Design, test, implement and test again form the four phases applied to iOS application testing.
  • โ˜‘๏ธ Prerequisites: A Mac running OS X with the Xcode IDE, an automation framework and the iOS SDK installed.
  • โœ… Instruments route: The Automation instrument records a script, shows it in the script log, and replays it on demand.
  • ๐Ÿงช OCUnit route: A Unit Test Bundle target, an active scheme, a test group and a test class written in Objective-C.
  • โš ๏ธ Deprecation: The UIAutomation instrument was deprecated in Xcode 8 and removed; XCUITest is the supported successor.
  • ๐Ÿ› ๏ธ Modern equivalent: A UI Testing Bundle target plus XCUIApplication queries replaces the recorded Instruments script.

iOS automation testing with the Xcode UI Automation framework running a recorded script against an app

iOS Automation Testing using Xcode

To guarantee the quality of your iOS application, you should follow the test-driven development process shown in the figure below.

Test-driven development cycle for iOS automation testing showing design, test, implement and re-test phases

Test-Driven Development (TDD) is a testing model which is applied to iOS application testing, and it sits inside the wider practice of mobile testing. In this model, a tester has to follow the 4 phases below:

  • Design: Figure out what you want to test and design your test cases.
  • Test: Run all tests and see if any test cases fail.
  • Implement: Revise your code and fix the bugs that caused the test to fail.
  • Test again: If a test fails, roll back to the design. If all test cases pass, the code meets the entire tested requirement.

Setting up Xcode Project for UI Testing

To create an iOS test program you need a Mac. Your Mac must already have the following installed:

  • OS X โ€” the operating system for a Mac.
  • Xcode IDE โ€” the development tool for iOS.
  • An automated testing framework โ€” UI Automation, OCUnit, and so on.
  • iOS SDK 4 or higher.

โš ๏ธ Version note: The prerequisites above describe the toolchain of the era in which the two walkthroughs that follow were written. On a current Mac, Xcode ships the XCTest and XCUITest frameworks in the box, and the separate UI Automation instrument is no longer part of the installation. The original steps are preserved below because they document how the framework worked, and the modern equivalent is described further down.

How to Create iOS Automation using UI Automation Framework

The eight steps below record a script with the Automation instrument and replay it against the application under test.

Step 1) Launch Instruments

Open XCode -> Open Developer Tool -> Instrument

Opening Instruments from the Xcode Open Developer Tool menu

Step 2) Add Automation Instrument

In the Instruments window, select the Automation instrument.

Selecting the Automation instrument in the Instruments template chooser

To create a test script, you either record a test scenario or you program it manually.

Step 3) Press Red button

An instrument is launching โ€” stop the recording immediately. If you want to start the recording, press the red button.

Red record button in the Instruments toolbar used to start and stop a trace

Step 4) Create a new script

In the Scripts window, click Add > Create to create a new script.

Add and Create menu in the Instruments Scripts window for a new automation script

Step 5) Choose the target

You are now in the Trace window. Use the Choose Target pull-down to navigate to the debugging version of your app.

Choose Target pull-down in the Instruments Trace window pointing at the debug build

In this case, Apple’s sample SimpleDrillDown app is used as the application under test. It has the GUI shown below.

SimpleDrillDown sample application interface used as the application under test

Step 6) Start record your script

Record your script by hitting the record button at the top or bottom of the tool.

Record button at the edge of the Instruments window that starts script capture

Now you can perform some UI actions on your application under test, and your script is recorded.

Step 7) See your script

To see your script, hit the Trace Log / Editor Log drop-down and switch to the script log view.

Trace Log and Editor Log drop-down used to switch to the script log view

You will see your recorded script.

Recorded UI Automation script displayed in the Instruments script log view

Step 8) Play your script

Press the play button. The script runs, and you can stop it after the logs appear.

Playback of the recorded automation script with log output in the Instruments window

โš ๏ธ Historical note: The Automation instrument used in these eight steps was deprecated in Xcode 8 and later removed, so it is no longer present in current Xcode installations. The steps are retained here as a record of how the framework worked; for new work, use the XCUITest walkthrough further down this page.

How to Create iOS Automation using OCUnit framework

The second route places the tests inside the Xcode project itself rather than inside Instruments.

Step 1) Start Xcode IDE, Add Unit Test Bundle target

Adding a Unit Test Bundle target to an existing Xcode project

Step 2) Write the name of the new Unit Test Bundle as shown in the figure above, then click Finish.

Step 3) Make Unit Test the active target

Selecting the unit test bundle as the active target in Xcode

Step 4) Add a group for test classes

Creating a project group to hold the iOS unit test classes

Step 5) Add a Unit test class

Adding a new unit test class file inside the test group in Xcode

Step 6) Now start your implementation

Empty unit test class in the Xcode editor ready for the test implementation

OCUnit uses the Objective-C language to create the test program, so the developer must know that language. Modern Xcode versions ship unit testing through XCTest instead, which supports both Objective-C and Swift, but the target-and-class structure shown in these six steps is unchanged.

UIAutomation vs XCUITest: What Changed

Because both frameworks used above belong to an earlier generation of the Apple toolchain, it is worth being precise about what replaced them and why.

Aspect UI Automation (Instruments) XCUITest
Status Deprecated in Xcode 8 and removed from later releases Apple’s supported UI testing framework
Where tests live Scripts inside an Instruments trace document A UI Testing Bundle target inside the Xcode project
Language JavaScript Swift or Objective-C
Test runner The Automation instrument XCTest, the same runner as unit tests
Continuous integration Awkward โ€” driven through Instruments Runs from the command line alongside unit tests
Recording Record button in the Instruments toolbar Record button in the Xcode editor, which emits Swift

The practical consequence is that an XCUITest suite is ordinary project source code. It is reviewed, versioned and executed like the rest of the codebase, which is the main reason the recorded-trace model disappeared.

How to Write an iOS UI Test with XCUITest

The modern equivalent of the eight Instruments steps is short. The structure below mirrors the same record-then-replay idea, but the output is a source file rather than a trace.

  1. Add the target. In Xcode choose File > New > Target and pick the UI Testing Bundle template, or tick the option to include tests when creating a new project.
  2. Open the generated test class. Xcode creates an XCTestCase subclass with empty setup and test methods.
  3. Launch the app under test. Create an XCUIApplication instance and call launch on it, which starts the app in a separate process.
  4. Query and act. Reach elements through the element queries โ€” buttons, tables, static texts โ€” and call tap, typeText or swipe on them.
  5. Assert. Use XCTAssert to verify that the expected element exists after the action.
  6. Run. Execute the test from the Xcode test navigator, or from the command line so the same suite runs in continuous integration.

A minimal test follows this shape:

import XCTest

final class AppUITests: XCTestCase {

    func testTappingFirstRowShowsDetail() {
        let app = XCUIApplication()
        app.launch()

        // act on the first row of the list
        app.tables.cells.element(boundBy: 0).tap()

        // verify that the next screen appeared
        XCTAssertTrue(app.staticTexts.firstMatch.waitForExistence(timeout: 5))
    }
}

The recorder still exists: placing the cursor inside a test method and pressing the record button in the editor generates these queries automatically, which is the direct descendant of Step 6 above. The wider principles of automation testing apply unchanged.

UI Automation Sample Code

This article includes some source code examples. They help you understand the tutorial more clearly and quickly.

UI Automation Sample โ€” test script for the UI Automation demo.

FAQs

No. Xcode and the iOS simulators run only on macOS, so a Mac is required either locally or as a hosted build machine. Cloud device farms and hosted CI providers exist precisely so teams without Mac hardware can still execute the suite.

Machine learning models suggest replacement element queries when a screen changes, cluster flaky failures by root cause, and rank which failed runs are genuine regressions. This matters for UI suites, where small layout edits otherwise break many selectors at once.

It handles the repetitive parts well โ€” test class scaffolding, launch arguments, page-object wrappers and assertion boilerplate. Element identifiers still have to match the real app, so every generated query needs verification against the running build before it is trusted.

Appium drives iOS through its XCUITest driver, which replaced the older UIAutomation driver. The advantage is one cross-platform test language for iOS and Android; the trade-off is an extra layer between the test and Apple’s own runner.

A unit test runs inside the app process and calls your code directly. A UI test launches the app as a separate process and interacts only through the interface, so it is slower but validates what the user actually experiences.

Simulators are faster and fine for most functional flows in a pipeline. Real devices are needed for camera, biometrics, push notifications, performance and anything touching hardware sensors, so most teams run both at different points in the cycle.

Each test relaunches the app and waits on animations. Stability improves when you set accessibility identifiers instead of matching on labels, wait for element existence rather than sleeping, reset state between tests, and keep each case focused on one journey.

Not directly, because the languages and element models differ. The usual path is to keep the old scripts as documentation of intended coverage, then rewrite each scenario as an XCUITest case, starting with the journeys that fail most often in production.

Summarize this post with: