Swift中如何在XCUITest场景下Swizzle Date(非NSDate)类型?
XCUITest运行时修改Date返回值实现方案
直接在XCUITest测试target里Swizzle Date的方法无法生效,因为XCUITest测试进程和App主进程是完全隔离的,测试代码里的方法交换不会作用到App运行逻辑中,可以通过以下两种方案实现需求:
方案1:注入可配置的时间提供者(推荐,稳定性最高)
这个方案不需要做危险的系统方法交换,对业务代码侵入极低,也不会影响线上逻辑:
- 首先在主App target中给Date扩展可覆写的时间获取入口,默认实现和系统
Date()行为完全一致:
extension Date { /// 时间获取提供者,生产环境默认返回系统当前时间 static var currentProvider: () -> Date = { Date() } /// 业务代码统一用这个方法获取当前时间 static func now() -> Date { currentProvider() } }
把业务代码中所有直接写let date = Date()的位置替换为let date = Date.now(),线上运行时返回值和原有逻辑完全一致,没有任何副作用。
- 在XCUITest测试代码启动App时,通过启动参数传入需要的时间偏移量,比如需要加2小时就传7200秒:
let app = XCUIApplication() // 传入时间偏移量,单位秒 app.launchArguments += ["-UITestTimeOffset", "7200"] app.launch()
- 在主App的启动入口(AppDelegate或SwiftUI App的初始化方法)中,检测到UITest启动参数时替换时间提供者:
// 检测UI测试环境配置 if let offsetValue = UserDefaults.standard.string(forKey: "UITestTimeOffset"), let timeOffset = TimeInterval(offsetValue) { Date.currentProvider = { Date().addingTimeInterval(timeOffset) } }
配置完成后,运行UI测试时所有调用Date.now()的位置都会自动返回偏移后的时间,示例中系统时间为2022/07/06 22:31时,拿到的时间就会是加2小时后的自定义时间,对应label显示符合预期。
方案2:Runtime Swizzle Date初始化方法(无业务代码侵入)
如果不想改动现有业务代码,可以在主App内通过方法交换修改Date的返回值,注意Swizzle逻辑必须写在主App target内,不能写在测试target:
- 同样通过上述启动参数的方式判断当前是否处于UI测试环境、需要偏移多少时间
- App启动时检测到测试参数就执行方法交换,代码示例:
import ObjectiveC.runtime // 先定义全局变量存储测试用时间偏移量 private var testTimeOffset: TimeInterval = 0 // 仅在UI测试环境下执行swizzle if let offsetValue = UserDefaults.standard.string(forKey: "UITestTimeOffset"), let timeOffset = TimeInterval(offsetValue) { testTimeOffset = timeOffset guard let originalMethod = class_getInstanceMethod( Date.self, #selector(Date.init) ), let swizzledMethod = class_getInstanceMethod( Date.self, #selector(Date.swizzled_init) ) else { return } method_exchangeImplementations(originalMethod, swizzledMethod) } extension Date { @objc func swizzled_init() -> Date { // 调用原实现获取真实系统时间,再加上自定义偏移 let realDate = self.swizzled_init() return realDate.addingTimeInterval(testTimeOffset) } }
注意:Swizzle系统基础类的初始化方法存在不可控风险,可能影响App内部系统API依赖时间的逻辑,非必要不优先使用这个方案。
内容的提问来源于stack exchange,提问作者PJR
相关产品推荐
相关产品推荐

