如何避免XCUITest扫描UIKit中大数据量UITableView的所有单元格?
问题
我正尝试使用XCUITest框架为iOS应用编写UI自动化测试。我的应用中有一个包含UITableView的页面,其数据源拥有3000多行数据。当我尝试查找该页面上的元素或点击按钮时,UI测试会陷入卡顿。
示例代码如下:
app.cells.element(boundBy: 0).firstMatch.exists
或
app.buttons["FilterButton"].firstMatch.tap()
检查主应用进程后,我发现应用正卡在一个漫长的循环中:逐个遍历3000多行数据,并调用tableView的方法:
func tableView(_ tableView: UITableView, cellForRowAt cellIndexPath: IndexPath) -> UITableViewCell
是否有办法避免XCUITest扫描UITableView中的全部单元格?
注:firstMatch属性本应避免此类层级查询,但在调用tap等操作时无效,因为XCUI引擎会扫描整个tableView以检查按钮上方是否存在遮挡元素。
解决方案
优化应用侧UITableView的数据源返回逻辑
在UITableView的代理方法中加入UI测试环境判断,当检测到当前是UI测试运行时,限制返回的数据源行数(比如只返回可见范围内的行数),避免全量加载单元格。示例代码:func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let isUITesting = ProcessInfo.processInfo.environment["UITESTING"] == "YES" if isUITesting { // 返回少量行数,比如10行,减少UI测试时的单元格渲染 return 10 } return dataSource.count }同时在UI测试的
setUp方法中注入环境变量:override func setUp() { super.setUp() let app = XCUIApplication() app.launchEnvironment["UITESTING"] = "YES" app.launch() }缩小元素查询范围
避免直接从app根节点开始查询,尽量定位到具体父容器后再查找目标元素。比如按钮在导航栏时,直接从导航栏节点查询:app.navigationBars.buttons["FilterButton"].firstMatch.tap()针对tableView的cell,可通过
containing方法结合可见元素定位,只查询当前屏幕内的单元格:app.cells.containing(.staticText, identifier: "VisibleCellContent").firstMatch.exists跳过XCUI的遮挡检查(慎用)
若确定目标元素不会被遮挡,可直接获取元素坐标模拟点击,跳过XCUI的全量扫描校验逻辑。示例代码:let filterButton = app.buttons["FilterButton"].firstMatch let centerCoordinate = filterButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)) centerCoordinate.tap()注意:此方法会跳过系统的可见性校验,可能导致点击实际不可见的元素,仅在场景安全时使用。
内容的提问来源于stack exchange,提问作者Herno
相关产品推荐
相关产品推荐

