文章目录- 一、测试用例设计
- 1、编写步骤
- 1、Arrange(准备)
- 2、Action(调用)
- 3、Assert(断言)
- 2、设计经验和原则
- 二、创建测试文件
- 三、断言方法
- 1、布尔值断言
- 2、空和非空断言
- 3、相等和不想等断言
- 4、可比值断言
- 5、异常断言
- 6、无条件测试失败
- 7、跳过测试
- 8、异步测试
- 四、查看单测覆盖率
- 五、性能测试
- 六、其他
- 1、为测试添加全局断点:
- 2、测试项目里的文件
- 3、私有属性和方法:
- 4、添加测试`Target`方法:
- 1、编写步骤
- 1、Arrange(准备)
- 2、Action(调用)
- 3、Assert(断言)
- 2、设计经验和原则
- 1、布尔值断言
- 2、空和非空断言
- 3、相等和不想等断言
- 4、可比值断言
- 5、异常断言
- 6、无条件测试失败
- 7、跳过测试
- 8、异步测试
- 1、为测试添加全局断点:
- 2、测试项目里的文件
- 3、私有属性和方法:
- 4、添加测试`Target`方法:
一、测试用例设计
1、编写步骤
1、Arrange(准备)
准备好所需要的外部环境,如数据、mock等。
2、Action(调用)
调用需要测试的方法或流程。
3、Assert(断言)
判断调用返回的结果是否符合预期。 例如:
代码语言:javascript复制func testDescForCount() {
// Arrange (准备)
let count = 0
// Action (调用)
let desc = MOUitl.descForCount(count);
// Assert (断言)
XCTAssertEqual(desc, "0")
}
2、设计经验和原则
- 正面测试、负面测试、特性测试、完善代码覆盖率
- 基于意图,而不是基于实现
- 简单、清晰、易懂(包括函数名和函数体)
- 避免引入条件判断、循环等逻辑
- 纯UI描述不需要写单元测试
- 数据逻辑需要写单元测试
- 复杂代码需要进行合理的拆分
- 通过单元测试优化代码架构
二、创建测试文件
一般来说,我们会为一个类
or一个类型的功能
创建一个测试类,继承自XCTestCase
。
下面来看一下这个类的几个方法:
代码语言:javascript复制override class func setUp() {} // 类的setUp方法,在所有方法执行之前执行
override class func tearDown() {} // 类的tearDown,在所有方法执行之后执行
// 在每个测试方法执行之前都会执行,用于对每个测试方法都需要做的初始化操作(有异常时会抛出:适用于初始化会有异常抛出的情况)
override func setUpWithError() throws {}
override func setUp() {} // 同上(执行顺序在setUpWithError之后)适用于初始化无异常抛出的情况
override func tearDown() {} // 同下(执行顺序在tearDownWithError之前)适用于清理无异常抛出的情况
// 在每个测试方法执行之后都会执行,用于对每个测试方法都需要做的清理操作(有异常时会抛出:适用于清理会有异常抛出的情况)
override func tearDownWithError() throws {}
// 自定义两个测试方法:
func testFuncation1() {}
func testFuncation2() {}
加上log后,看一下执行顺序如下:
注意:测试方法必须是以
test
为前缀的,否则无法测试
三、断言方法
1、布尔值断言
Boolean Assertions
:
XCTAssert
:断言为 trueXCTAssertTrue
:断言为 trueXCTAssertFalse
:断言为 false
例如:
代码语言:javascript复制// 断言为选中状态
XCTAssert(self.vc.subscribeButton.isSelected)
// 断言为选中状态
XCTAssertTrue(self.vc.subscribeButton.isSelected)
// 断言为未选中状态
XCTAssertFalse(self.vc.subscribeButton.isSelected)
2、空和非空断言
Boolean Assertions
:
XCTAssertNil
:断言为nilXCTAssertNotNil
:断言不为nil
例如:
代码语言:javascript复制// 断言button为nil
XCTAssertNil(self.vc.subscribeButton)
// 断言button为不为nil
XCTAssertNotNil(self.vc.subscribeButton)
3、相等和不想等断言
Equality and Inequality Assertions
:
XCTAssertEqual
:断言两个对象相等XCTAssertNotEqual
:断言两个对象不相等
例如:
代码语言:javascript复制// 断言 两个对象 相等
XCTAssertEqual(self.subscribeButton, self.vc.subscribeButton)
// 断言 两个对象 不相等
XCTAssertNotEqual(self.subscribeButton, self.subscribeButton2)
4、可比值断言
Comparable Value Assertions
:
XCTAssertGreaterThan
:断言大于某个值XCTAssertGreaterThanOrEqual
:断言大于等于某个值XCTAssertLessThanOrEqual
:断言小于等于某个值XCTAssertLessThan
:断言小于某个值
例如:
代码语言:javascript复制// 断言num2大于num1
XCTAssertGreaterThan(self.vc.num2, self.vc.num1)
// 断言num2大于等于num1
XCTAssertGreaterThanOrEqual(self.vc.num2, self.vc.num1)
// 断言num1小于num2
XCTAssertLessThan(self.vc.num1, self.vc.num2)
// 断言num1小于等于num2
XCTAssertLessThanOrEqual(self.vc.num1, self.vc.num2)
5、异常断言
NSException Assertions
:
XCTAssertThrowsError
:断言会抛出异常XCTAssertNoThrow
:断言不会抛出异常
例如:
代码语言:javascript复制XCTAssertNoThrow(self.vc.viewDidLoad())
XCTAssertThrowsError(self.vc.viewDidLoad())
6、无条件测试失败
NSException Assertions
:
XCTFail
:立即无条件生成一个失败
例如:
代码语言:javascript复制XCTFail()
7、跳过测试
Skipping Tests
:
XCTSkipIf
:如果条件为false,继续执行测试XCTSkipUnless
:如果条件为true,继续执行测试XCTSkip
:抛出跳过执行Error
举例:
代码语言:javascript复制func testSkipping() throws {
guard self.vc.isCanTests else {
throw XCTSkip("Can't test vc")
}
try XCTSkipIf(!self.vc.isCanTests, "Can't test vc")
try XCTSkipUnless(self.vc.isCanTests, "Can't test vc")
XCTAssert(self.vc.isCanTests)
}
8、异步测试
明确是否需要验证异步逻辑
Asynchronous Tests
:
XCTestExpectation
:期望XCTWaiter
:等待n个期望
举例:
代码语言:javascript复制// 为异步下载任务创建一个期望
let expectation = XCTestExpectation(description: "Download apple.com home page")
let url = URL(string: "https://apple.com")!
let dataTask = URLSession.shared.dataTask(with: url) { (data, _, _) in
// 断言下载数据不为nil
XCTAssertNotNil(data)
// 完成预期
expectation.fulfill()
}
dataTask.resume() // 开始下载任务
// 等待:知道完成预期 or 超时
wait(for: [expectation], timeout: 3.0) // 超时时间不要设置过长
// 失败情况1:下载的data为nil
// 失败情况2:下载任务在3s内未完成
四、查看单测覆盖率
需要在Edit Scheme
-> Test
-> Options
-> Code Coverage
-> 勾上,才能看得到:
查看位置:
还有编辑器右边也能查看当前测试是否执行该行代码,或者是执行了几遍,显示位置如下图:
五、性能测试
measure
闭包可以测试其括号内代码的性能:执行时长
func testPerformanceExample() throws {
measure {
for _ in 0...1000 {
MOPerson(name: "momo", age: 18)
}
}
}
这样写完会提示:No baseline average for Time
,此时需要设置一下对该段代码期望的运行时间,设置方式如下图:
设置完之后,再测试一遍该方法,就能看到满足期望的比例了:
六、其他
1、为测试添加全局断点:
2、测试项目里的文件
Swift
项目,当我们需要使用一个类时,Xcode
会报找不到类型的错:Cannot find type 'MOTestsViewController' in scope
需要做的:
步骤1:需要在Target
-> Build Phases
-> Compile Sources
中点击
,加入你需要测试的文件,如下图:
步骤2:在测试文件的头部导入目标项目,例如:
代码语言:javascript复制@testable import MOSurveySwift
3、私有属性和方法:
Swift
无法测试私有属性和方法:(以下是官网Tips
)
Note: @testable provides access only for internal functions; file-private and private declarations are not visible outside of their usual scope when using @testable.
- OC`的私有属性和方法,可以在当前测试用分类再次声明一下就可以测试了
4、添加测试Target
方法:
方法一:在创建项目时勾选 方法二:在导航栏的测试tab添加:如图
Demo github地址
参考:官方文档