目录
<a name="前言"></a>前言
在日常的开发中,单元测试是很关键的一环。因为它可以帮你省去很多的重复测试工作,特别是在接口上(防止后台坑你..,也防止自己坑自己)。即使在第一个版本开发时间急的情况下,也得在第二个版本补上。
<a name="断言语法"></a>断言语法
单元测试的关键点在于 "断言"。在"XCTest"类中,你可以看到全部的断言。本篇文章将全部采用swift语言讲解。
-
XCTAssert : 最常用的断言
- 如 XCTAssert(1 < 2) 可通过
-
XCTAssertEqual : 断言 "="
- 如 XCTAssertEqual("1", "1") 可通过
-
XCTAssertEqualWithAccuracy : 断言 "=" 允许误差
- 如 XCTAssertEqualWithAccuracy(1, 2, accuracy: 1) 可通过
-
XCTAssertFalse 断言 "flase"
- 如 XCTAssertFalse(false) 可通过
-
XCTAssertTrue 断言 "true"
- 如 XCTAssertTrue(true) 可通过
-
XCTAssertGreaterThan 断言 ">"
- 如 XCTAssertGreaterThan(2, 1) 可通过
-
XCTAssertGreaterThanOrEqual 断言 ">="
- 如 XCTAssertGreaterThanOrEqual(1, 1) 可通过
-
XCTAssertLessThan 断言 "<"
- 如 XCTAssertLessThan(1, 2) 可通过
-
XCTAssertLessThanOrEqual 断言 "<="
- 如 XCTAssertLessThanOrEqual(1, 2) 可通过
-
XCTAssertNotEqual 断言 "!="
- 如 XCTAssertNotEqual(1, 2) 可通过
-
XCTAssertNotEqualWithAccuracy 断言 "!=" 允许误差
- 如 XCTAssertNotEqualWithAccuracy(1, 2, 0.5) //1 + 0.5(误差) != 2 可通过
-
XCTAssertNotNil 断言 "! = nil"
- 如 XCTAssertNotNil(1) 可通过
XCTAssertThrowsError 直接抛出错误,不通过
XCTFail 直接测试失败 不通过
<a name="配置"></a>配置
在测试文件中有两个初始的方法setUp 和 tearDown。
- setUp 在每个测试被调用都会调用,所以一般涌来配置一些设置,如网络请求配置。
- tearDown 在测试被调用之后调用,一般不需要关心。
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
<a name="添加测试"></a>添加测试
在项目中的test文件中添加 以test开头的函数即可,如:
func testCommon() {
XCTAssertTrue(1 < 2)
}
然后点击左上角的执行图标,就可以测试啦。
如下图
测试结果为绿色的图标就是测试通过。
如下图
如果测试不通过,对应的代码会报错。
如下图
当然你还可以通过侧栏对其全部或单个测试。
如下图
<a name="异步测试"></a>异步测试
项目中不仅仅用到上面那种简单测试,也会碰到接口测试这种需要时间的测试!因单元测试时串行的一个个函数执行,我们肯定不能让某个测试无限时的执行下去。下面我们用sleep来模拟接口请求。
func testMyOne() {
//设置失败原因
var expecta:XCTestExpectation? = expectation(description: "expecta")
let queue = DispatchQueue.global()
queue.async {
//网络请求
sleep(2)
//断言
XCTAssertEqual("1", "1")
//执行成功
expecta?.fulfill()
expecta = nil
}
//超时限制
self.waitForExpectations(timeout: 1, handler: nil)
}
执行以上的代码你会发现测试不通过
如下图
因sleep(2)了两秒,而超时的限制只有一秒,故在达到限制时间1s的时候expecta?.fulfill()这个成功标示还没执行到,就会报错。把timeout时间改大一点就可以通过测试。
要是把 expecta?.fulfill() 这行成功标示的代码放到sleep(2)的上面,则测试会通过。因在限制时间1s期限到时,expecta?.fulfill()已经得到执行,故判定为成功。如下图
<a name="通知测试"></a>通知测试
除了上面的异步方式,还可以用通知测试,如下面代码所示,sleep(2)超过了限制时间1S,测试将不通过。将限制时间改为>=2S即可通过测试。
func testMyTwo() {
var expecta:XCTestExpectation? = expectation(description: "notification")
//监听通知
let noti = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "notification"), object: nil, queue: nil) { (not) -> Void in
DispatchQueue.global().async {
//网络请求
sleep(2)
//断言
XCTAssertEqual("1", "1")
//测试成功
expecta?.fulfill()
expecta = nil
}
}
//同步的写在这边,全局异步写 (1)和 (2)都没问题。 //(1)
//self.waitForExpectations(timeout: 1,handler: nil)
//发送通知
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notification"), object: nil)
//超时限制
self.waitForExpectations(timeout: 1,handler: nil) //异步的写在这边也无所谓 //(2)
//删除通知
NotificationCenter.default.removeObserver(noti)
}
注意点:
在执行不是并行异步的的sleep情况下,waitForExpectations 要在发送通知前,不然限制时间是不管用的,这涉及到多线程的知识,有兴趣的可以看我的另外一篇文章 GCD 细细的读
在异步和通知模式时,是以在超时前能执行到fulfill() 判定成功
<a name="总结"></a>总结
会以上的这些知识,足够应对日常开发的单元测试了,欢迎讨论。