Swift自动化测试:如何存储随机PIN实现APP重启后复用?
解决方案
核心问题在于你当前的getRandomPin是懒加载属性,每次访问(包括APP重启后测试类重新初始化)都会重新洗牌生成新的PIN;且你存储的是UI元素对象,APP重启后这些元素引用会失效。需要改为存储PIN的数字值,并通过持久化方式保留,避免重复生成。
方案1:测试类静态属性存储(同会话内持久)
适合同一个测试类内的多个用例,APP重启后测试会话未中断的场景:
import XCTest class YourTestClass: XCTestCase { // 静态属性存储PIN数字,属于类而非实例,不会随实例销毁消失 static var savedPinDigits: [Int]? private let app = XCUIApplication() private lazy var randomPinButtons: [XCUIElement] = [ app.otherElements["pinEnter_digit0"], app.otherElements["pinEnter_digit1"], app.otherElements["pinEnter_digit2"], app.otherElements["pinEnter_digit3"], app.otherElements["pinEnter_digit4"], app.otherElements["pinEnter_digit5"], app.otherElements["pinEnter_digit6"], app.otherElements["pinEnter_digit7"], app.otherElements["pinEnter_digit8"], app.otherElements["pinEnter_digit9"] ] // 生成或获取已存储的PIN数字数组 private func getOrGeneratePinDigits() -> [Int] { if let saved = Self.savedPinDigits { return saved } // 生成4位不重复随机数字(若允许重复可改用randomElement循环) let newPin = (0...9).shuffled().prefix(4).map { $0 } Self.savedPinDigits = newPin return newPin } func enterPIN() -> Self { let pinDigits = getOrGeneratePinDigits() for digit in pinDigits { randomPinButtons[digit].tap() } return self } // 可选:测试结束后清理存储 override func tearDown() { super.tearDown() Self.savedPinDigits = nil } }
方案2:UserDefaults存储(跨会话/完全重启持久)
适合APP完全重启、跨测试类的场景,存储系统会保留数据直到主动清理:
import XCTest class YourTestClass: XCTestCase { private let app = XCUIApplication() private let defaults = UserDefaults.standard private let pinStorageKey = "AutomationTestPIN" private lazy var randomPinButtons: [XCUIElement] = [ app.otherElements["pinEnter_digit0"], app.otherElements["pinEnter_digit1"], app.otherElements["pinEnter_digit2"], app.otherElements["pinEnter_digit3"], app.otherElements["pinEnter_digit4"], app.otherElements["pinEnter_digit5"], app.otherElements["pinEnter_digit6"], app.otherElements["pinEnter_digit7"], app.otherElements["pinEnter_digit8"], app.otherElements["pinEnter_digit9"] ] private func getOrGeneratePinDigits() -> [Int] { if let saved = defaults.array(forKey: pinStorageKey) as? [Int] { return saved } let newPin = (0...9).shuffled().prefix(4).map { $0 } defaults.set(newPin, forKey: pinStorageKey) return newPin } func enterPIN() -> Self { let pinDigits = getOrGeneratePinDigits() for digit in pinDigits { randomPinButtons[digit].tap() } return self } override func tearDown() { super.tearDown() // 测试结束后清理存储,避免影响后续测试 defaults.removeObject(forKey: pinStorageKey) } }
关键注意事项
- 不要存储UI元素对象:APP重启后,原有的XCUIElement引用会失效,必须通过数字值重新定位元素
- 若允许PIN包含重复数字,可将生成逻辑改为:
let newPin = (0..<4).map { _ in Int.random(in: 0...9) } - 静态属性方案仅在同一个测试会话内有效,UserDefaults方案可跨会话保留数据
内容的提问来源于stack exchange,提问作者Aleksandr Tverdovskiy
相关产品推荐
相关产品推荐

