替换UISwitch为自定义MySwitch后如何构造匹配它的XCUIElementQuery
问题原因
默认XCUIElement.switches查询只会匹配accessibilityRole为.switch的可访问性元素,你替换为自定义MySwitch后查询失效,是因为该类没有正确配置可访问性属性,或是重写了默认的开关角色导致系统无法识别。
实现方案
1. 配置MySwitch的可访问性属性
首先保证MySwitch能被系统识别为开关类型,同时增加专属标识区分原生UISwitch:
import UIKit // 自定义trait,用于标识MySwitch类型,选择系统未占用的位避免冲突 extension UIAccessibilityTraits { static let mySwitch = UIAccessibilityTraits(rawValue: 1 << 24) } class MySwitch: UISwitch { // 如果是完全自定义继承UIControl的开关也适用 override init(frame: CGRect) { super.init(frame: frame) setupAccessibility() } required init?(coder: NSCoder) { super.init(coder: coder) setupAccessibility() } private func setupAccessibility() { // 保留开关角色,保证系统switches查询可以匹配到 accessibilityRole = .switch // 插入自定义trait,用于单独查询MySwitch accessibilityTraits.insert(.mySwitch) // 如果是完全自定义的非UISwitch子类开关,还要加下面的配置保证XCUI开关相关API可用 // accessibilityValue = isOn ? "1" : "0" // 切换开关状态时同步更新accessibilityValue即可 } }
2. 扩展XCUI查询能力
在UI测试目标下扩展XCUIElementTypeQueryProvider,实现你需要的两种查询:
import XCTest extension XCUIElementTypeQueryProvider { // 系统原生switches查询已经可以匹配到设置了.switch角色的MySwitch,无需额外修改 // 新增自定义查询仅返回MySwitch实例 var mySwitches: XCUIElementQuery { // 匹配所有开关类型下带自定义trait的元素 let mySwitchPredicate = NSPredicate(format: "accessibilityTraits & %lu != 0", UIAccessibilityTraits.mySwitch.rawValue) return descendants(matching: .switch).matching(mySwitchPredicate) } }
使用说明
配置完成后就可以直接调用你需要的查询接口:
someElement.switches:返回当前元素下所有原生UISwitch和自定义MySwitch实例someElement.mySwitches:仅返回当前元素下所有自定义MySwitch实例
注意事项
- 不要修改
MySwitch的accessibilityRole为其他值,否则会从系统开关查询中消失 - 自定义trait使用24位及以上的预留位即可,不会和系统内置trait冲突
- 如果你不想用自定义trait,也可以通过统一给MySwitch的
accessibilityIdentifier增加固定前缀,修改predicate为匹配前缀即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Jamie A
相关产品推荐
相关产品推荐

