如何在XCTest框架中根据测试用例结果触发任务并传失败标识?
解决Swift XCTest测试失败时触发自定义方法并传入失败标识的问题
我来帮你搞定这个需求~要实现测试用例失败时触发自定义任务(比如截图)并传入指定的失败ID,这里有两种可靠的实现方式,一步步给你说明:
方法一:重写XCTestCase的recordFailure方法(适配现有断言代码)
XCTest框架在断言失败时会自动调用recordFailure(withDescription:inFile:atLine:expected:)方法,我们可以重写这个方法来捕获失败事件,并从你现有断言的描述文本里提取标记的失败ID(比如你用的---10385格式)。
修改你的测试类代码如下:
import Foundation import XCTest class HomePageChromeUITests: XCTestCase { var pathStr:String = "" override func setUp() { super.setUp() continueAfterFailure = false self.launchWithUserLoggedIn() } override func tearDown() { super.tearDown() } // 重写失败记录方法,捕获断言失败事件 override func recordFailure(withDescription description: String, inFile filePath: String, atLine lineNumber: Int, expected: Bool) { // 先调用父类方法,保证XCTest默认的失败记录行为正常执行 super.recordFailure(withDescription: description, inFile: filePath, atLine: lineNumber, expected: expected) // 从断言描述中提取失败ID(匹配"---xxxx"格式) if let failureID = extractFailureID(from: description) { // 调用自定义的失败处理方法 handleTestFailure(withFailureID: failureID) } } // 自定义失败处理方法,这里可以添加截图等业务逻辑 private func handleTestFailure(withFailureID failureID: String) { print("测试失败,失败ID:\(failureID)") // 示例:添加截图逻辑 let screenshot = XCUIScreen.main.screenshot() // 可将截图保存到指定路径,文件名带上失败ID便于区分 let savePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! .appendingPathComponent("failure_screenshot_\(failureID).png") try? screenshot.pngRepresentation.write(to: savePath) } // 解析断言描述中的失败ID private func extractFailureID(from description: String) -> String? { // 匹配"---"后面的数字序列 let pattern = #"---(\d+)"# guard let regex = try? NSRegularExpression(pattern: pattern), let match = regex.firstMatch(in: description, range: NSRange(description.startIndex..., in: description)) else { return nil } let range = Range(match.range(at: 1), in: description) return range.map { String(description[$0]) } } func testHomePageChrome_10385() { let app = XCUIApplication() let backButton = app.buttons[AccessibilityIdentifiers.PageEditorBackButton] let editButton = app.buttons[AccessibilityIdentifiers.PageEditorEditButton] XCTAssertTrue(backButton.exists && backButton.frame.origin.x < editButton.frame.origin.x, "Back button does not exist.---10385") XCTAssertTrue(!editButton.exists, "Edit button does not exist.---10385") } }
这个方案不需要修改你现有的断言代码,只要保持断言描述里的---失败ID格式,就能自动提取ID并触发处理逻辑。
方法二:自定义断言函数(更可控、更可靠)
如果不想依赖字符串解析,我们可以自己封装断言函数,直接通过参数传递失败ID,这样逻辑更清晰,也避免了因为描述格式变化导致的解析错误:
import Foundation import XCTest class HomePageChromeUITests: XCTestCase { var pathStr:String = "" override func setUp() { super.setUp() continueAfterFailure = false self.launchWithUserLoggedIn() } override func tearDown() { super.tearDown() } // 自定义断言函数:验证条件为true,失败时触发处理方法 private func XCTAssertTrueWithFailureID(_ expression: @autoclosure () throws -> Bool, failureID: String, _ message: String = "", file: StaticString = #filePath, line: UInt = #line) { do { guard try expression() else { // 先触发失败处理逻辑 handleTestFailure(withFailureID: failureID) // 调用原生XCTFail抛出失败 XCTFail(message, file: file, line: line) return } } catch { handleTestFailure(withFailureID: failureID) XCTFail("断言执行出错:\(error)", file: file, line: line) } } // 自定义失败处理方法 private func handleTestFailure(withFailureID failureID: String) { print("测试失败,失败ID:\(failureID)") // 示例:添加截图并保存 let screenshot = XCUIScreen.main.screenshot() let desktopPath = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first! let screenshotPath = desktopPath.appendingPathComponent("failure_\(failureID).png") try? screenshot.pngRepresentation.write(to: screenshotPath) } func testHomePageChrome_10385() { let app = XCUIApplication() let backButton = app.buttons[AccessibilityIdentifiers.PageEditorBackButton] let editButton = app.buttons[AccessibilityIdentifiers.PageEditorEditButton] // 使用自定义断言,直接传入失败ID XCTAssertTrueWithFailureID(backButton.exists && backButton.frame.origin.x < editButton.frame.origin.x, failureID: "10385", "Back button does not exist.") XCTAssertTrueWithFailureID(!editButton.exists, failureID: "10385", "Edit button does not exist.") } }
这个方案的优势是逻辑更直接,不需要依赖字符串解析,失败ID的传递更可靠,也方便后续扩展其他断言类型(比如XCTAssertEqualWithFailureID)。
额外提示
如果需要在测试通过或被跳过时也触发任务,可以重写testRun方法,监听测试的状态变化:
override var testRun: XCTestRun? { didSet { // 监听测试状态,比如测试完成后判断状态 testRun?.completionBlock = { [weak self] in guard let self = self else { return } switch self.testRun?.testStatus { case .passed: self.handleTestPassed() case .skipped: self.handleTestSkipped() default: break } } } } private func handleTestPassed() { print("测试通过") // 添加通过时的任务逻辑 } private func handleTestSkipped() { print("测试被跳过") // 添加跳过的任务逻辑 }
内容的提问来源于stack exchange,提问作者Automation User
相关产品推荐
相关产品推荐

