1、KIF介绍
KIF的全称是Keep it functional。它是一个建立在XCTest的UI测试框架,通过accessibility来定位具体的控件,再利用私有的API来操作UI。由于是建立在XCTest上的,所以你可以完美的借助XCode的测试相关工具(包括命令行脚本
使用KIF框架强制要求你的代码支持accessibility。如果你之前没接触过,可以看看Apple的文档Accessibility Programming Guide for iOS。
简单来说,accessibility能够让视觉障碍人士使用你的App。每一个控件都有一个描述AccessibilityLabel。在开启VoiceOver的时候,点击控件就可以选中并且听到对应的描述。通常UIKit的控件是支持accessibility的,自定定义控件可以通过代码或者Storyboard上设置。
2、KIF使用
1)cocopod导入KIF框架
pod 'KIF', '~> 3.0'
2)在创建的UI测试文件中导入,测试类继承类改成 KIFTestCase
import KIF
3)在项目中进行配置
(1)“Build Phases”:
设置 Target Dependencies , UI 自动化测试固然要依赖应用程序的 App 产物,所以需保证应用程序 Target 被添加在 Test Target 的 Target Dependencies 中。
(2)“Build Settings”:
设置 “Bundle loader” 为:$(BUILT_PRODUCTS_DIR)/MyApp.app/MyApp;
设置 “Test Host” 为:$(BUILT_PRODUCTS_DIR); 设置 “Wrapper Extensions” 为:xctest。
4)配置控件的AccessibilityLabel属性
有3种配置方式
(1)通过Runtime Attributes设置(KVC)
(2)通过GUI来设置,选中控件,找到下图所示的位置,填写AccessibilityLabel属性
(3)通过代码来设置
kifBtn.accessibilityLabel = "KIF"
5)具体使用
(1)KIF时OC写的,Swift无法直接使用其关键方法tester、system(通过宏定义),参照GitHub README,通过extension实现
在UI测试文件中书写
extension XCTestCase {
func tester(file : String = #file,_ line : Int = #line)->KIFUITestActor{
return KIFUITestActor(inFile: file, atLine: line, delegate: self)
}
func system(file : String = #file,_ line : Int = #line)->KIFSystemTestActor{
return KIFSystemTestActor(inFile: file, atLine: line, delegate: self)
}
}
(2)KIF的使用
操作步骤:
点击button按钮-->跳转至登录界面-->输入用户名、密码,点击login-->跳转至tab导航界面,切换不同tab的操作流程
class LoginTestCase: KIFTestCase {
/// 所有测试进行前调用,可以做一些必要或者共有的初始化操作
override func beforeAll() {
}
/// 测试点击登陆后进入其他View
func test00Login() {
tester().tapView(withAccessibilityLabel: "button")
tester().waitForView(withAccessibilityLabel: "login")
let nameTextField = tester().waitForView(withAccessibilityLabel: "UserName") as! UITextField
let pwdTextField = tester().waitForView(withAccessibilityLabel: "Password") as! UITextField
tester().enterText("User", intoViewWithAccessibilityLabel: "UserName")
tester().enterText("123456", intoViewWithAccessibilityLabel: "Password")
// 点击
tester().tapView(withAccessibilityLabel: "login")
XCTAssertTrue(!nameTextField.text!.isEmpty, "User name can't be nil")
XCTAssertTrue(!pwdTextField.text!.isEmpty, "Password can't be nil")
// 等待某个View出现,也可以通过该函数得到该View的实例
tester().waitForView(withAccessibilityLabel: "Scene1")
}
/// 测试切换不同的View
func test01TabButtons() {
tester().tapView(withAccessibilityLabel: "Tab2")
tester().waitForView(withAccessibilityLabel: "Scene2")
tester().tapView(withAccessibilityLabel: "Tab3")
tester().waitForView(withAccessibilityLabel: "Scene3")
}
/// 测试输入
func test02Input() {
tester().tapView(withAccessibilityLabel: "Tab1")
tester().waitForView(withAccessibilityLabel: "InputTextField")
// 输入文字
tester().enterText("Hello KIF", intoViewWithAccessibilityLabel: "InputTextField")
// TODO: 如何确定键盘弹出的done按钮的accessibilityLabel?
tester().tapView(withAccessibilityLabel: "Scene1View")
// 得到View实例
let textfield = tester().waitForView(withAccessibilityLabel: "InputTextField") as! UITextField
// 判断是否相等
XCTAssertEqual(textfield.text, "Hello KIF")
// 清除当前文字重新输入新的
tester().clearText(fromAndThenEnterText: "Test Geometry", intoViewWithAccessibilityLabel: "InputTextField")
tester().tapView(withAccessibilityLabel: "Scene1View")
}
/// 有的时候无法确定accessibilityLabel或者是自定义的空间没有accessibilityLabel,可以使用Geometry计算位置进行
func test03Geometry() {
tester().wait(forTimeInterval: 2)
let stepper = tester().waitForView(withAccessibilityLabel: "stepper") as! UIStepper
let stepCenter = stepper.window?.convert(stepper.center, from: stepper.superview)
// 算出-和+的位置
var minusButton = stepCenter
minusButton?.x -= stepper.frame.width / 4
var plusButton = stepCenter
plusButton?.x += stepper.frame.width / 4
for _ in 0 ..< 10 {
tester().wait(forTimeInterval: 1)
tester().tapScreen(at: minusButton!)
}
// 延时1秒
tester().wait(forTimeInterval: 1)
tester().tapScreen(at: plusButton!)
tester().wait(forTimeInterval: 1)
tester().tapScreen(at: plusButton!)
tester().wait(forTimeInterval: 1)
// 设置超时时间(默认为10秒)
KIFUITestActor.setDefaultTimeout(60)
tester().tapView(withAccessibilityLabel: "Tab2")
KIFUITestActor.setDefaultTimeout(10)
}
}
参考地址: