什么是UI Tests
UI Tests是一个自动测试UI与交互的Testing组件
作用
按照规则编写代码,实现对视图、按钮、文字框等控件的自动操作。
随着应用功能的增多,工程规模变大,单纯地靠人工操作来覆盖测试用例的效率是不够的,尤其是在产品迭代时修改了旧功能或加入了新功能,大量的重复工作使得回归测试的成本也会变高,需要UI Tests来进行自动页面测试。
实现方式
1. 创建工程。
创建Project, 勾选include UI Tests. 或在已有项目中,添加target,选择iOS > Test > Cocoa Touch UI Testing Bundle。
工程中增加了这个部分:
打开UITestDemoUITests.m文件,可以看到三个函数:
setUp
在其他方法之前调用。tearDown
在其他方法运行完之后调用。testExample
包含测试的代码
2.编写测试代码。
选择测试文件后,点击testExample函数内区域,使光标停留在函数内(表示录制操作的代码会在这里显示)。点击录制按钮(下方红色的圆点),app开始在模拟器上运行,开始对app进行操作,系统会在这个文件中自动生成测试代码。结束录制,按测试需求修改代码。
3.开始测试
点击testExample函数名左边的播放按钮,开始自动测试,然后可以看到app正按照代码来进行自动操作。同时手机(or simulator)桌面上会出现一个叫UITestDemoUITest(即“app名称+UITest)的app,但这个app点开是黑的貌似没有什么交互。
4.定位测试error
当测试失败时,需要定位错误。在Xcode左侧菜单里,点击最右边的按钮“Show the Report Navigator”
红色的部分表示存在错误,点击展开可以看到更详细的说明。
图中指出,在找一个叫”Inpu your phone number”的TextField的时候出现错误,没有找到这个对象,仔细检查发现少打了一个t (我当然是故意的)。修改后UI测试可以正常运行。
5.常见问题
有时候开始测试会出现test failed情况,:
例如:NSInternalInconsistencyException’ when running UITesting with Xcode 7
解决方式:Xcode > Preference > Locations > Advanced
选择Custom,右侧选Relative to Workspace和Absolute都可以(而选Relative to Derived Data会失败, 囧)
关于Location > Advanced的设置具详细介绍,请戳这里
测试元素的语法
XCUIApplication
在UI Testing中代表整个app对象。包含两个主要方法:
- launch 启动程序
- terminate 终止程序
XCUIDevice
- +sharedDevice 创建设备的实例。
- orientation 返回UIDeviceOrientation枚举值。
XCUIElement
继承自NSObject
协议:XCUIElementAttributes, XCUIElementTypeQueryProvider
是 app 中的 UI 元素在测试框架中的代理,用来穿件查询以定位元素。我们不能直接通过得到的 XCUIElement 来直接访问被测 app 中的元素,而只能通过 Accessibility 中的像是 identifier 或者 frame 这样的属性来获取 UI 的信息。
exist:
可以让你判断当前的UI元素是否存在,如果对一个不存在的元素进行操作,会导致测试组件抛出异常并中断测试descendantsMatchingType(type:XCUIElementType)->XCUIElementQuery:
取某种类型的元素以及它的子类集合childrenMatchingType(type:XCUIElementType)->XCUIElementQuery:
取某种类型的元素集合,不包含它的子类tap(): 点击
doubleTap(): 双击
pressForDuration(duration: NSTimeInterval):
长按一段时间,在你需要进行延时操作时,这个就派上用场了swipeUp():
这个响应不了pan手势,暂时没发现能用在什么地方,也可能是beta版的bug,先不解释typeText(text: String): 用于textField和textView输入文本时使用,使用前要确保文本框获得输入焦点,可以使用tap()函数使其获得焦点
实例代码:Demo工程点此去下载
- (void)testExample {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
XCUIApplication *app = [[XCUIApplication alloc] init];
// textFields交互
XCUIElement *inputNameTextField = app.textFields[@"Input your name"];
XCTAssert(inputNameTextField.exists);
[inputNameTextField tap];
[inputNameTextField typeText:@"name"];
XCUIElement *inputPhoneNumberTextField = app.textFields[@"status"];
[inputPhoneNumberTextField tap];
[inputPhoneNumberTextField typeText:@"begin"];
// buttons交互
[app.buttons[@"Cancel"] tap];
XCUIElement *doneButton = app.buttons[@"DONE"];
[doneButton doubleTap];
// labels交互
[app.staticTexts[@"Switch0"] tap];
[app.staticTexts[@"Switch1"] tap];
// switch交互
// first switch
XCUIElementQuery *inputYourNameElementsQuery = [app.otherElements containingType:XCUIElementTypeTextField identifier:@"Input your name"];
XCUIElement *switch0 = [[[inputYourNameElementsQuery childrenMatchingType:XCUIElementTypeSwitch] matchingIdentifier:@"1"] elementBoundByIndex:0];
[switch0 tap];// 打开
XCUIElement *switch1 = app.switches[@"0"];
[switch1 tap];// 关闭
[switch0 tap];// 打开
[switch1 tap];// 关闭
XCUIElement *switch2 = [[[inputYourNameElementsQuery childrenMatchingType:XCUIElementTypeSwitch] matchingIdentifier:@"1"] elementBoundByIndex:1];
[switch2 tap];// 打开
[switch1 tap];// 关闭
[switch2 tap];// 打开
[switch1 tap];// 关闭
// table交互
XCUIElementQuery *tablesQuery = [[XCUIApplication alloc] init].tables;
XCUIElement *index1CellStaticText = tablesQuery.staticTexts[@"index: 0 cell"];
[index1CellStaticText swipeUp];
[index1CellStaticText swipeDown];
[index1CellStaticText tap];
[index1CellStaticText swipeLeft];
[index1CellStaticText swipeRight];
[index1CellStaticText pressForDuration:2.3];
}