You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 18:34:56