iOS 业界有很多 UI 自动化测试框架,美团有一篇文章中对主流框架进行了对比,各大框架实现的思路有两种:基于苹果的 UI Testing(UI Automation)或者使用私有 API。这里只介绍苹果自家的 UI Testing,它是苹果自 Xcode 7 引入的 UI 自动化测试框架,有几个优势:
- Xcode 自带,不需要搭建环境
- 支持 OC、Swift,学习成本低
- 支持 WebView 测试
- 稳定性好
利用 UI Testing 可以对 app 的 UI 进行黑盒测试。目前还只能做比较简单的测试工作,基本原理是利用 iOS 的 Accessibility(原本是为帮助残障人士提供的框架)来查找 UI 上的元素并模拟点按、滚动等事件,配合对 UI 元素状态的校验来检查测试结果。
使用方法
要使用 UI Testing,只需要新建一个 UI Testing 的 target,Xcode 已经提供了现成的模板,非常方便。整个过程就三步:利用 XCUIApplication 和 XCUIElementQuery 查找元素、用 XCUIElement 模拟操作、用断言检查结果。
XCUIApplication
XCUIApplication 代表整个应用,可以用来启动、结束进程,或者传入一些启动参数,最常用的功能是利用 XCUIApplication 实例来查询 UI 上的元素。
1 | XCUIApplication *app = [[XCUIApplication alloc] init]; |
XCUIElementQuery
XCUIElementQuery 代表一系列的 UI 元素查询条件,可以级联使用。常用的使用方法如下:
1 | // 查找所有的 collectionView 的 cell, collectionViews 和 cells 是 XCUIElementQuery 提供的方法 |
通常一个页面中相同种类的 UI 元素很多,就需要使用 accessibilityIdentifier 来区分不同的元素。
XCUIElement
XCUIElement 代表具体的 UI 元素,比如一个 button 或者 scrollView。从 XCUIElementQuery 可以得到 XCUIElement。
1 | // 获取第一个 button |
我们还可以通过 XCUIElement 的属性查询 UI 元素的状态,比如是否可点击,是否存在。得到 UI 元素调用 tap,swipeUp 等方法就可以模拟操作了,使用起来非常方便。除了向指定元素模拟操作之外,还可以使用 XCUICoordinate 模拟基于屏幕坐标的事件。
UI Testing 是基于 XCTest 开发的,也就可以用 XCTest 提供的一系列断言用来检查结果,如 XCTAssert、XCTAssertTrue 等。
常见问题
accessibilityIdentifier 没有设置
TBUIAutoTest 是一个自动生成 accessibilityIdentifier 的工具,原理是 hook UIView 的 accessibilityIdentifier 和 accessibilityLabel 方法,通过运行时获取成员变量名来作为 accessibilityIdentifier。
如何实现暂停 3 秒钟
测试代码是运行在另外一个进程中的,所以 sleep(3) 就好。
iOS 11 上向可见的元素发送事件报错,提示元素不可见
现象:执行 tap 操作时报 error: Error -25204 performing AXAction 2003 on element pid: 43616, elementOrHash.elementID: 4882574576.240,cell hittable 返回 NO
原因:isAccessibilityElement 方法默认返回 YES,在 iOS 11 上会出现返回 NO 的情况(同样代码 iOS 12 上正常)
解决:需要显示将该属性设置为 YES
SO:https://stackoverflow.com/questions/46819807/xcode-ui-testing-collection-view-cells-became-non-hittable-on-ios-11
DOMException Crash
现象:WebView 加载过程中 crash
原因:WebView 加载过程中查找 UI 元素会导致 crash
解决:
- 使用 WKWebView
- 在
UIWebViewDelegate中,webView 加载完成前调用[self.view setAccessibilityElementsHidden:YES],加载完成后调用[self.view setAccessibilityElementsHidden:NO] - sleep 几秒等待 webView 加载完成 :]
被测试 app 如何判断正在进行 UI Test?
在启动 app 时增加一个启动参数,在 app 中读取。
1 | // 测试代码 |