Testing with XCTest
Testing with XCTest
Write unit tests to verify logic and UI tests to automate end-to-end flows using the XCTest framework.
Unit Tests
Create a tests target in Xcode and add test cases that extend XCTestCase.
Syntax: class MyTests: XCTestCase { func testSomething() { XCTAssertEqual(...) } }
Example
import Foundation
struct Math {
static func add(_ a: Int, _ b: Int) -> Int { a + b }
}
import XCTest
@testable import MyApp
final class MyTests: XCTestCase {
func testAdd() {
XCTAssertEqual(Math.add(2, 3), 5)
}
}
This example defines a pure function and a unit test verifying the result with XCTAssertEqual.
Test Target Setup
- Add a Unit Testing Bundle target in Xcode (File → New → Target).
- Keep test files under the tests target; import your app with
@testable importwhen needed. - Use Target Membership to choose whether a file belongs to the app or tests.
Writing Tests (AAA)
Arrange your inputs, Act by calling the code under test, Assert on the result.
Example
import XCTest
@testable import MyApp
final class MyTests: XCTestCase {
func testAdd() {
// Arrange
let a = 2, b = 3
// Act
let sum = Math.add(a, b)
// Assert
XCTAssertEqual(sum, 5)
}
}
XCTAssert Variants
Assert on conditions and values.
XCTAssertEqual,XCTAssertNotEqualXCTAssertTrue,XCTAssertFalseXCTAssertNil,XCTAssertNotNilXCTAssertThrowsError,XCTAssertNoThrow
Async Tests
Wait for asynchronous work to complete.
Example
import XCTest
final class AsyncTests: XCTestCase {
func testExpectation() {
let exp = expectation(description: "async work")
DispatchQueue.global().async {
// simulate work
exp.fulfill()
}
wait(for: [exp], timeout: 1.0)
}
}
Performance Tests
Measure execution time and memory usage.
Example
import XCTest
final class PerformanceTests: XCTestCase {
func testSortPerformance() {
let input = Array(0..<10_000).shuffled()
measure {
_ = input.sorted()
}
}
}
Test Plans & CI
Organize configurations (schemes, destinations, diagnostics) and run tests in CI with xcodebuild test targeting a simulator device.
- Use Test Plans to organize configurations (schemes, destinations, diagnostics).
- Run tests in CI with
xcodebuild testtargeting a simulator device. - Prefer deterministic tests; mock network and time; parallelize where possible.
UI Tests
Use XCUIApplication to launch the app and interact with UI elements by accessibility.
Syntax:
let app = XCUIApplication(); app.launch()- query elements with
app.buttons["Label"] - assert with
XCTAssertTrue(...)
Example
import SwiftUI
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 12) {
Text("Count: \(count)")
Button("Increment") { count += 1 }
}
.padding()
}
}
import SwiftUI
struct ContentView: View {
var body: some View { CounterView() }
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
import XCTest
final class MyUITests: XCTestCase {
func testIncrementButtonIncrementsCount() {
let app = XCUIApplication()
app.launch()
let increment = app.buttons["Increment"]
XCTAssertTrue(increment.exists)
increment.tap()
XCTAssertTrue(app.staticTexts["Count: 1"].exists)
}
}
This example launches the app, taps a button, and verifies that a label exists.
Tip: Prefer small, deterministic tests; avoid relying on network by stubbing or using test doubles.