mcpField
X
xcuitest-skill

xcuitest-skill

github.com/lambdatest测试与质量384240 次安装2 周前更新
代码仓库

关于 xcuitest-skill

xcuitest-skill 为 iOS QA 工程师提供 XCUITest 自动化测试指引,涵盖本地模拟器与 TestMu AI 云端执行,并整理 Swift 测试模式和实践建议。

主要功能

  1. 01Swift 测试与元素查询
  2. 02点击、输入及手势操作
  3. 03断言与系统弹窗处理
  4. 04页面对象模式及反模式
  5. 05本地与 TestMu AI 云端运行

适用场景

  1. 01编写 iOS 登录界面测试
  2. 02等待并验证界面元素
  3. 03处理权限弹窗
  4. 04从 Xcode 或命令行运行测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lambdatest/agent-skills --skill xcuitest-skill

安装后在 Claude Code 中输入/xcuitest-skill确认已加载。

附带文件reference/advanced-patterns.mdreference/playbook.md

详细介绍

XCUITest 自动化技能

你是一名专攻 XCUITest 的资深 iOS QA 工程师。

步骤 1 — 执行目标

├─ Mentions "cloud", "TestMu", "LambdaTest", "device farm"?
│  └─ TestMu AI cloud (upload IPA + test runner)
│
├─ Mentions "simulator", "local", "Xcode"?
│  └─ Local: Xcode Test Navigator or xcodebuild
│
└─ Default → Local simulator

核心模式 — Swift

基本测试
import XCTest

class LoginTests: XCTestCase {
    let app = XCUIApplication()

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

    func testLoginWithValidCredentials() {
        let emailField = app.textFields["emailInput"]
        XCTAssertTrue(emailField.waitForExistence(timeout: 5))
        emailField.tap()
        emailField.typeText("[email protected]")

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

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

        let dashboard = app.staticTexts["Welcome"]
        XCTAssertTrue(dashboard.waitForExistence(timeout: 10))
    }

    func testLoginWithInvalidCredentials() {
        app.textFields["emailInput"].tap()
        app.textFields["emailInput"].typeText("[email protected]")
        app.secureTextFields["passwordInput"].tap()
        app.secureTextFields["passwordInput"].typeText("wrong")
        app.buttons["loginButton"].tap()

        let error = app.staticTexts["Invalid credentials"]
        XCTAssertTrue(error.waitForExistence(timeout: 5))
    }
}
元素查询
// By accessibility identifier (best)
app.buttons["loginButton"]
app.textFields["emailInput"]

// By label text
app.staticTexts["Welcome back"]
app.buttons["Submit"]

// By predicate
app.buttons.matching(NSPredicate(format: "label CONTAINS 'Login'")).firstMatch

// By index
app.cells.element(boundBy: 0)

// Existence check
let element = app.buttons["submit"]
XCTAssertTrue(element.waitForExistence(timeout: 10))
操作
element.tap()                           // Tap
element.doubleTap()                     // Double tap
element.press(forDuration: 2)           // Long press
element.typeText("hello")              // Type (field must be focused)
element.swipeUp()                       // Swipe
element.swipeDown()
element.swipeLeft()
element.swipeRight()
element.pinch(withScale: 2, velocity: 1)  // Zoom in
element.rotate(CGFloat.pi, withVelocity: 1) // Rotate
断言
XCTAssertTrue(element.exists)
XCTAssertTrue(element.isHittable)
XCTAssertTrue(element.isEnabled)
XCTAssertEqual(element.label, "Expected Label")
XCTAssertEqual(element.value as? String, "Expected Value")
XCTAssertTrue(element.waitForExistence(timeout: 10))
处理系统弹窗
// Auto-handle permission dialogs
addUIInterruptionMonitor(withDescription: "Permission Alert") { alert in
    if alert.buttons["Allow"].exists {
        alert.buttons["Allow"].tap()
        return true
    }
    return false
}
app.tap() // Trigger the monitor
页面对象模式
protocol Page {
    var app: XCUIApplication { get }
}

class LoginPage: Page {
    let app: XCUIApplication

    init(app: XCUIApplication) { self.app = app }

    var emailField: XCUIElement { app.textFields["emailInput"] }
    var passwordField: XCUIElement { app.secureTextFields["passwordInput"] }
    var loginButton: XCUIElement { app.buttons["loginButton"] }
    var errorLabel: XCUIElement { app.staticTexts["errorMessage"] }

    func login(email: String, password: String) -> DashboardPage {
        emailField.tap()
        emailField.typeText(email)
        passwordField.tap()
        passwordField.typeText(password)
        loginButton.tap()
        return DashboardPage(app: app)
    }
}
反模式
不推荐推荐原因
sleep(5)waitForExistence(timeout:)不可靠
未等待就查询元素始终先调用 waitForExistence竞态条件
硬编码点击坐标无障碍标识符屏幕尺寸各不相同
在一个庞大的方法中测试编写小而专注的测试方法隔离性更好
TestMu AI Cloud
# 1. Create .ipa from Xcode: Product → Archive → Distribute → Ad Hoc
# 2. Upload app and test runner
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
  -X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
  -F "[email protected]" -F "type=ios"

curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
  -X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
  -F "[email protected]" -F "type=ios"

# 3. Execute on real devices
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
  -X POST "https://mobile-api.lambdatest.com/framework/v1/xcui/build" \
  -H "Content-Type: application/json" \
  -d '{
    "app": "lt://APP123",
    "testSuite": "lt://TEST456",
    "device": ["iPhone 16-18", "iPhone 15 Pro-17"],
    "build": "XCUITest Cloud Build",
    "video": true, "deviceLog": true
  }'

快速参考

任务命令
从 Xcode 运行⌘U 或 Product → Test
从 CLI 运行xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 16'
运行特定测试xcodebuild test -only-testing:MyAppUITests/LoginTests/testLogin
截图let screenshot = XCUIScreen.main.screenshot()
附件let attachment = XCTAttachment(screenshot: screenshot)
启动参数app.launchArguments = ["--uitesting"]
启动环境变量app.launchEnvironment = ["ENV": "test"]

深入模式

有关高级模式、调试指南、CI/CD 集成和最佳实践, 请参阅 reference/playbook.md。

评论

支持 Markdown