بنقرة واحدة
ios-testing-patterns
// XCTest and XCUITest execution workflows and flaky test detection patterns
// XCTest and XCUITest execution workflows and flaky test detection patterns
| name | ios-testing-patterns |
| description | XCTest and XCUITest execution workflows and flaky test detection patterns |
| version | 0.0.1 |
| token_cost | ~40 |
Comprehensive guide to XCTest and XCUITest execution, analysis, and flaky test detection
This skill provides patterns and workflows for executing iOS tests using XCTest and XCUITest frameworks. It covers test execution strategies, result analysis, flaky test detection, and troubleshooting common test failures.
Use this skill when:
| Task | Operation | Key Parameters |
|---|---|---|
| Run all tests | test | scheme, destination |
| Run specific test | test | scheme, only_testing |
| Skip tests | test | scheme, skip_testing |
| Use test plan | test | scheme, test_plan |
| Parallel execution | test | destination (multiple) |
Use ios-testing-patterns when:
Related Skills:
XCTest (Unit/Integration Tests):
XCUITest (UI Tests):
Sequential Execution:
Parallel Execution:
Test Sharding:
Basic Unit Test Execution:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15,OS=18.0"
}
Note: The destination parameter now supports auto-resolution! You can omit the OS version (e.g., "platform=iOS Simulator,name=iPhone 15") and the tool will automatically select the latest available OS version for that device.
Run Specific Test Class:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15,OS=18.0",
"options": {
"only_testing": ["MyAppTests/NetworkTests"]
}
}
Run Specific Test Method:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15,OS=18.0",
"options": {
"only_testing": ["MyAppTests/NetworkTests/testAPIRequest"]
}
}
Basic UI Test Execution:
{
"operation": "test",
"scheme": "MyAppUITests",
"destination": "platform=iOS Simulator,name=iPhone 15"
}
UI Tests with Specific Device:
{
"operation": "test",
"scheme": "MyAppUITests",
"destination": "platform=iOS Simulator,name=iPad Pro (12.9-inch)"
}
UI Tests with Test Plan:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"test_plan": "SmokeTests"
}
}
Multiple Destinations:
Run tests on multiple simulators simultaneously:
{
"operation": "test",
"scheme": "MyApp",
"destination": [
"platform=iOS Simulator,name=iPhone 15",
"platform=iOS Simulator,name=iPhone SE (3rd generation)"
],
"options": {
"parallel": true
}
}
Parallel Test Benefits:
Parallel Test Considerations:
Skip Specific Tests:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"skip_testing": [
"MyAppUITests/SlowTests",
"MyAppTests/NetworkTests/testLargeDownload"
]
}
}
Run Only Fast Tests:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"only_testing": ["MyAppTests/UnitTests"],
"skip_testing": ["MyAppTests/UnitTests/testSlowOperation"]
}
}
Success Response:
{
"success": true,
"tests_run": 45,
"tests_passed": 45,
"tests_failed": 0,
"execution_time": "12.4s",
"scheme": "MyApp"
}
Failure Response:
{
"success": false,
"tests_run": 45,
"tests_passed": 43,
"tests_failed": 2,
"failures": [
{
"test": "MyAppTests.LoginTests.testInvalidPassword",
"message": "XCTAssertEqual failed: (\"error\") is not equal to (\"invalid\")",
"file": "LoginTests.swift",
"line": 42
},
{
"test": "MyAppUITests.CheckoutTests.testPaymentFlow",
"message": "Failed to find button \"Confirm\"",
"file": "CheckoutTests.swift",
"line": 78
}
],
"execution_time": "18.7s"
}
Analyzing Test Results:
success statustests_failed countfailures array for detailsexecution_time for performance issuesWhat are Flaky Tests?
Tests that intermittently pass or fail without code changes:
Detection Strategy 1: Multiple Runs
Run tests multiple times to detect flakiness:
# Run tests 5 times and compare results
for i in {1..5}; do
execute_xcode_command(test, scheme, destination)
# Record results
done
Detection Strategy 2: Pattern Analysis
Look for common flaky test patterns:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"only_testing": ["MyAppTests/SuspectedFlakyTest"]
}
}
Flaky Test Indicators:
Flaky Test Workflow:
1. Identify suspect test (intermittent failures)
2. Run test 10+ times in isolation
3. Analyze failure patterns
4. Check for:
- Hard-coded waits (sleep/wait)
- Expectation timeouts too short
- Shared mutable state
- Network dependencies
- Animation timing assumptions
5. Fix root cause
6. Verify with repeated runs
Clean State Before Tests:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"clean_before_build": true
}
}
Reset Simulator State:
# Use simulator-workflows skill
execute_simulator_command(operation: "erase", udid: <device-udid>)
Test Isolation Best Practices:
setUp() and tearDown() methodsTypical Test Scheme Setup:
Multiple Test Plans:
UnitTests.xctestplan → Fast unit tests only
UITests.xctestplan → UI automation tests
SmokeTests.xctestplan → Critical path tests
RegressionTests.xctestplan → Full test suite
Pattern 1: Test Fixtures
class TestData {
static let validUser = User(name: "Test", email: "test@example.com")
static let invalidUser = User(name: "", email: "invalid")
}
Pattern 2: Factory Methods
extension User {
static func makeTestUser(name: String = "Test") -> User {
return User(name: name, email: "\(name)@test.com")
}
}
Pattern 3: Test Database
class TestDatabase {
func setupTestData() {
// Create known test data
}
func teardownTestData() {
// Clean up after tests
}
}
UI Test Screenshot Pattern:
override func setUp() {
continueAfterFailure = false
}
override func tearDown() {
if let testRun = testRun, testRun.failureCount > 0 {
let screenshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: screenshot)
attachment.lifetime = .keepAlways
add(attachment)
}
}
Execute Tests with Screenshots:
{
"operation": "test",
"scheme": "MyAppUITests",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"result_bundle_path": "./TestResults.xcresult"
}
}
XCTest Performance Measurement:
func testPerformance() {
measure {
// Code to measure
performExpensiveOperation()
}
}
Performance Test Execution:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"only_testing": ["MyAppTests/PerformanceTests"]
}
}
Causes:
Solutions:
Causes:
Solutions:
Example Fix:
// Bad: Immediate query may fail
app.buttons["Submit"].tap()
// Good: Wait for element
let submitButton = app.buttons["Submit"]
XCTAssert(submitButton.waitForExistence(timeout: 5))
submitButton.tap()
Causes:
Solutions:
Example Fix:
// Bad: May timeout
wait(for: [expectation], timeout: 1.0)
// Good: Reasonable timeout
wait(for: [expectation], timeout: 10.0)
Causes:
Solutions:
UI Test Timeouts:
{
"operation": "test",
"scheme": "MyAppUITests",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"test_timeout": 600
}
}
Common Timeout Scenarios:
App Launch Timeout: App takes too long to launch
Element Query Timeout: UI element not found
Network Timeout: API requests fail
Animation Timeout: Waiting for animation
Symptom: Tests fail due to simulator state
Common Issues:
Solutions:
# Erase simulator before tests
execute_simulator_command({
"operation": "erase",
"udid": "<simulator-udid>"
})
# Then run tests
execute_xcode_command({
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15"
})
Symptom: Tests pass individually but fail in suite
Causes:
Solutions:
override func setUp() {
super.setUp()
// Reset all shared state
AppState.shared.reset()
clearDatabase()
}
// Bad: Shared state
class APIManager {
static let shared = APIManager()
}
// Good: Dependency injection
class APIManager {
// Inject per test
}
{
"operation": "test",
"scheme": "MyApp",
"options": {
"test_order": "random"
}
}
Always isolate tests:
tearDown()Example:
class UserTests: XCTestCase {
var sut: UserManager!
override func setUp() {
super.setUp()
sut = UserManager()
}
override func tearDown() {
sut = nil
super.tearDown()
}
func testCreateUser() {
// Test uses fresh sut instance
}
}
Optimize test speed:
UI Test Speed:
// Disable animations for faster tests
app.launchArguments += ["DISABLE_ANIMATIONS"]
Use descriptive test names:
// Bad
func test1() { }
// Good
func testLoginWithValidCredentialsSucceeds() { }
func testLoginWithInvalidPasswordShowsError() { }
func testCheckoutWithEmptyCartDisplaysWarning() { }
Structure tests clearly:
func testAddItemToCart() {
// Arrange
let cart = ShoppingCart()
let item = Product(name: "Test", price: 10)
// Act
cart.add(item)
// Assert
XCTAssertEqual(cart.items.count, 1)
XCTAssertEqual(cart.total, 10)
}
Use consistent test data:
struct TestFixtures {
static let validEmail = "test@example.com"
static let invalidEmail = "invalid"
static let testUser = User(name: "Test", email: validEmail)
}
CI Test Workflow:
1. Clean build environment
2. Build app for testing
3. Boot fresh simulator
4. Run test suite
5. Collect code coverage
6. Parse test results
7. Archive test artifacts
8. Report results
CI Test Command:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"clean_before_build": true,
"code_coverage": true,
"result_bundle_path": "./TestResults.xcresult"
}
}
Maintain proper test distribution:
/\
/UI\ ← Few, slow, broad
/----\
/Integ\ ← Some, medium, focused
/------\
/ Unit \ ← Many, fast, isolated
/----------\
Recommended ratio:
Enable coverage collection:
{
"operation": "test",
"scheme": "MyApp",
"destination": "platform=iOS Simulator,name=iPhone 15",
"options": {
"code_coverage": true
}
}
Coverage goals:
Track test metrics:
When to investigate:
xc://operations/test: Complete test operations referencexc://reference/xctest: XCTest framework documentationxc://reference/xcuitest: XCUITest framework documentationxc://patterns/flaky-tests: Flaky test detection patternsTip: Isolate tests, mock dependencies, and run tests frequently during development.
Xcode build system guidance for xcodebuild operations. Use when building iOS projects, running tests, analyzing build failures, or configuring schemes. Covers build/clean/test operations, interpreting xcodebuild output, and troubleshooting common build errors.
iOS Simulator device and app management with simctl. Use when managing simulator devices (boot, create, delete), installing/launching apps, or troubleshooting simulator issues. Covers device lifecycle, app lifecycle, and diagnostics.
Accessibility-first UI automation using IDB. Query accessibility tree (fast, 50 tokens) before screenshots (slow, 170 tokens). Use when automating simulator interactions, tapping UI elements, finding buttons, or testing user flows. Covers idb-ui-describe, idb-ui-tap, idb-ui-find-element patterns.
WCAG compliance testing and accessibility quality assurance workflows for iOS apps. Use when validating accessibility labels, testing VoiceOver compatibility, checking contrast ratios, or ensuring WCAG 2.1 compliance. Covers accessibility tree analysis, semantic validation, and automated accessibility testing patterns.
Crash log analysis, symbolication, and debugging workflows for iOS apps. Use when investigating app crashes, analyzing crash reports, symbolicating stack traces, or identifying root causes. Covers crash log retrieval, symbolication with dSYM files, stack trace analysis, and common crash patterns.
Instruments integration and performance analysis workflows for iOS apps. Use when profiling CPU usage, memory allocation, network activity, or energy consumption. Covers Time Profiler, Allocations, Leaks, Network instruments, and performance optimization strategies.