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 上的元素。
XCUIApplication *app = [[XCUIApplication alloc] init];[app launch];[app terminate];
XCUIElementQuery
XCUIElementQuery 代表一系列的 UI 元素查询条件,可以级联使用。常用的使用方法如下:
// 查找所有的 collectionView 的 cell, collectionViews 和 cells 是 XCUIElementQuery 提供的方法XCUIElementQuery *cells = app.collectionViews.cells;// 使用 NSPredicate 为查询条件增加条件XCUIElementQuery *cells = [app.collectionViews.cells matchingPredicate:[NSPredicate predicateWithFormat:@"identifier LIKE '?labelPrice?'"]];// 使用下标来通过 accessibilityIdentifier 查询元素XCUIElementQuery *cells = app.collectionViews.cells[@"some_id"];
通常一个页面中相同种类的 UI 元素很多,就需要使用 accessibilityIdentifier 来区分不同的元素。
XCUIElement
XCUIElement 代表具体的 UI 元素,比如一个 button 或者 scrollView。从 XCUIElementQuery 可以得到 XCUIElement。
// 获取第一个 buttonXCUIElement *firstButton = [buttons elementBoundByIndex:0];// 等待 button 出现[button waitForExistenceWithTimeout:3]
我们还可以通过 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 中读取。
// 测试代码XCUIApplication *app = [[XCUIApplication alloc] init];app.launchEnvironment = @{@"isUITest" : @YES};[app launch];// app 代码+ (BOOL)isUITesting {NSDictionary *environment = [[NSProcessInfo processInfo] environment];return [environment[@"isUITest"] boolValue];}
