Comprehensive Guide to iOS UI Automation Testing with XCUITest, Appium, and Macaca
This article provides a detailed overview of iOS UI automation testing, covering XCUITest fundamentals, Accessibility considerations, sample Swift code, manual and recorded test case creation, command‑line toolchains, Web Service‑based architecture, and a comparison of Appium and Macaca for building scalable, CI‑integrated mobile testing platforms.
The author, after a year at Trip.com, shares extensive experience in iOS UI automation testing, organizing the content into four main parts: XCUITest principles, a Web Service‑based testing platform architecture, a comparison of Appium and Macaca, and the current state of Trip.com’s automation efforts.
XCUITest Principle Details – XCUITest, introduced by Apple in 2015, works together with the Accessibility framework. The Test App (a daemon process) drives the Host App via XCUIApplication , and only elements exposed to VoiceOver are discoverable unless developers set isAccessibilityElement and appropriate identifiers.
Demo Project – A minimal Swift demo creates four UI elements (UIImageView, UILabel, UIView, UIButton) with accessibilityIdentifier and demonstrates how to launch tests using the UITests target. The full source code is shown below:
import UIKit
class ViewController: UIViewController {
lazy var testImageView: UIImageView = {
let testImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
testImageView.backgroundColor = .red
testImageView.accessibilityIdentifier = "test imageview"
return testImageView
}()
lazy var testLabel: UILabel = {
let testLabel = UILabel(frame: CGRect(x: 0, y: 130, width: 100, height: 20))
testLabel.backgroundColor = .green
testLabel.text = "test label"
return testLabel
}()
lazy var testView: UIView = {
let testView = UIView(frame: CGRect(x: 0, y: 170, width: 100, height: 50))
testView.backgroundColor = .blue
testView.accessibilityIdentifier = "test view"
return testView
}()
lazy var testButton: UIButton = {
let testButton = UIButton(frame: CGRect(x: 0, y: 230, width: 100, height: 50))
testButton.backgroundColor = .yellow
testButton.setTitle("测试按钮", for: .normal)
return testButton
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(testImageView)
view.addSubview(testLabel)
view.addSubview(testView)
view.addSubview(testButton)
}
}The code creates four view instances, assigns accessibility identifiers, and adds them to the main view. The article explains how only elements with proper Accessibility settings become visible to the testing framework.
Accessibility Tools – Developers can use Xcode’s Accessibility Inspector (via Open Developer Tool → Accessibility Inspector ) to view the element hierarchy, verify isAccessibilityElement and other properties, and ensure UI elements are testable.
Manual Test Cases – A sample XCTest case demonstrates launching the app, locating elements by their identifiers, and asserting their existence using XCTAssertTrue . The test also measures launch performance.
import XCTest
class UITestDemoUITests: XCTestCase {
override func setUpWithError() throws { /* ... */ }
override func tearDownWithError() throws { /* ... */ }
func testExample() throws {
let app = XCUIApplication()
app.launch()
let label = app.staticTexts["test label"]
XCTAssertTrue(label.exists)
let button = app.buttons["测试按钮"]
XCTAssertTrue(button.exists)
let imgview = app.images["test imageview"]
XCTAssertTrue(imgview.exists)
let view = app.otherElements["test view"]
XCTAssertTrue(view.exists)
}
func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, *) {
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
}Recorded Test Generation – Xcode can record user interactions and generate corresponding UI test code, simplifying the creation of complex test cases.
Command‑Line Toolchains – The article lists essential CLI tools for iOS automation, including xcodebuild (for building and testing), xcrun simctl (simulator control), ideviceinstaller (real‑device app management), and ios-deploy (device deployment). Sample commands for building, testing, installing, launching, and uninstalling apps are provided.
Web Service‑Based Architecture – To improve script reuse across platforms, the author describes a two‑layer architecture: a command‑dispatch Web Service (RESTful API) and a UI‑driver layer (Appium’s WebDriverAgent for iOS or XCTestWD). The Web Service forwards test commands to the driver, which executes them on devices and returns results. This design enables distributed testing via Jenkins clusters.
Appium vs. Macaca – Both frameworks rely on XCUITest and Accessibility. Appium’s driver is written in Objective‑C, has a larger community, and is more actively maintained; Macaca’s driver is Swift‑based, with a smaller ecosystem. Installation steps, server startup commands, and capability configuration examples for both tools are included.
Trip.com Automation Practices – The company employs three testing strategies: smoke tests (quick CI checks for build stability), exploratory tests (white‑box/gray‑box tests using Google eDistantObject and EarlGrey), and a UI automation platform built on Macaca (gradually migrating to Appium). Metrics such as test duration, concurrency, case count, and pass rates are shared to illustrate efficiency gains.
Conclusion – iOS UI automation hinges on XCUITest and Accessibility. Building a Web Service‑driven platform adds cross‑platform support, easy deployment, and high concurrency, reducing manual effort and improving test reliability.
References to official Apple documentation, WWDC videos, and various blog posts are listed at the end of the article.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.