关于这个新框架你可能知道的首要事情之一就是文档的缺乏. iOS 9 和 Xcode 7 都没有包含 UI 测试的任何官方的文档。幸运的是,新的 XCU* 类中的大多数都拥有良好的注释的头文件。借助于 appledoc,我可以把这些头文件拖入 Xcode 兼容 Dash 的文件集合中。只要把资源库 clone 下来,将文件打开;默认的文档浏览器就会添加这些新的 API。你还可以在线查看文档。
UI 测试位于 XCTest 框架,添加了4个新的类,1个新的协议,以及3个新的常量。
启动 App - XCUIApplication这是用来启动你要测试的应用程序的主要拉钩。你可创建一个新的实例,[[XCUIApplication alloc] init], 然后在它上面调用 -launch。 如果你向应用添加了一个新的 UI 测试目标,就会在模板里面看见一个示例。在启动之前,你可以通过设置 -launchArguments 或者 -launchEnvironment 属性来分别设定一个特殊的参数或者环境变量。这样会创建一个漂亮的布局,例如,向你的 HTTP 客户端告知,在测试时访问一个模拟的服务器.
XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"USE_MOCK_SERVER" ];
[app launch];
你还可以 -terminate 你的 app,但我还没有发现过对那个东西的使用。
访问设备 - XCUIDevice你可以使用 +sharedDevice 创建这个对象的一个新实例。唯一可以被公共的访问到的属性是-orientation,它会返回普通的 UIDeviceOrientation 枚举值。虽然这是一个可读可写的属性,但是对他进行了设置并不会对模拟器的界面进行更新。我不确定这是不是我正在使用的 beta 版的一个 bug。
元素查询 - XCUIElementQuery这将是 UI 测试中使用率最高的一类,因它可用来构建查询以定位元素。还记得 UI 自动化里的 app.tableViews[0].cells[0] 吗?二者极其相似。
[[app.tables.element.cells elementAtIndex:4] tap];
每次调用堆栈都会返回一个可被链接在一起的查询对象,这就让控制应用程序变得更加精确。提到-element(元素),你便会说“我知道这儿只有一个,我要的就是这个”。你还可以通过特定的标签来访问堆栈中的对象。
[app.tables.element.cells[@"Call Mom"].buttons[@"More"] tap];
这种便捷的方式将通过 -elementMatchingType:identifier: 和 XCUIElementTypeAny,以及你传递的字符串来实现。如果想要更精确地控制所有选择,通过元素查询 XCUIElementType 将是最佳的方式。
与元素进行交互 - XCUIElement元素是封装了需要在一个应用程序中动态放置一个用户界面的相关信息的对象。元素用查询的方式被描述。 当调用到一个事件API, 元素就会被解析到。如果发现有0个或者多个匹配,就会冒出一个错误。
创建一个 XCUIElementQuery 的方式,会给予你元素的引用。除非你真的到了要与其交互的时候,框架是不会实际去应用的层级中找寻它们的。 这样为你带来了保持干净的测试的好处——你可以保留一个查询的引用,在测试的不同地方重用它。元素只会在交互期间才会被查找,这样就为你节省了再一次深入获取的花费。
交互都被进行了恰当的命名,会像你所期望的那样执行动作。例如,在 iOS 中你可以使用 -tap, -pressForDuration:, -swipeUp, 以及 -twoFingerTap。 如果你测试的是一个 OS X 应用,你可以对应地使用-click* 交互. 你甚至还可以使用 +performWithKeyModifiers:block: 来模拟持续的按下 ⌘ 按键.
断言一个测试框架里怎么可能没有断言?由于 UI 测试只是 XCTest 的扩展,所有已有的断言仍然管用,你仍然可以使用像 XCTAssert(),XCTAssertEquals(),和 XCTAssertNotNil() 这样的断言宏。
检查某个元素是否存在
一个快速的方法就是在一个元素对象上进行非空断言测试:
XCTAssertNotNil(app.buttons[@"Submit"]);
但是,elementMatchingType:identifier:总是返回一个对象,在这这个函数解析完之前,由它来决定了一个元素是否真的与查询相匹配,这说明这个测试总是通过的。作为替代,在断言中通过在元素上调用 -exist 方法来包装一下,像这样:
XCTAssert(app.buttons[@"Submit"].exists);
另一个建议就是自始至终都不用断言,那���在运行测试的时候如果解析出的查询结果并不能匹配到一个元素则测试就会自动失败。如果想这样做,别忘了在 setup 方法里关闭(注释)[XCTestCase -continueAfterFailure] 这项。
调试