unit test 的必要性
unit test 能干什么,怎么写,可以参考 这里 ,Apple 提供的一个简单的示例代码,用于测试一个计算器的 model。把标准的 MVC 架构改成 MVVM 架构后,viewModel 也是可以测试的,这里不谈。
unit test 可以有效解决开发中写好的代码不敢改的问题。另外针对比较复杂的 model ,先写测试代码再写实现代码也是一个更高效的办法。
杂项
资源文件
有时测试需要使用一些缓存数据或者准备好的数据库,引用这些文件的时候用 [NSBundle bundleForClass:[self class]]
替代 [NSBundle mainBundle]
,如果还是找不到,在 unit test 对应的 target 的 copy bundle resource 里面看一下是否有添加进去
测试用例不是共享的
一个 XCTestCase 下面每一个 test 方法会单独创建一个 XCTestCase 对象去执行, -setup
和 -tearDown
也会每个测试用例调用一次。
按一般类的直觉来说应该是这样
var foo = 1
func testfc1 {
print(foo) // 1
foo = foo + 1
}
func testfc2 {
print(foo) // 2
}
但是实际上
var foo = 1
func testfc1 {
print(foo) // 1
foo = foo + 1
}
func testfc2 {
print(foo) // 1
}
某些情况需要注意这个特性,比如测试数据库相关的代码,感觉测试后应用已经停止运行了,数据库连接关不关无所谓,但是测试的时候你会发现成吨的报错信息,每个测试用例在没有关闭连接的情况下又新创建了一个,所以最好在 - tearDown
里面关掉链接 [_queue close]
延时测试
需要测试延时任务(多线程、网络连接)的时候,需要用到 XCTestExpectation
类,具体使用可以去其他文章搜索一下,简单的代码如下所示
XCTestExpectation *expectation = [self expectationWithDescription:@"des"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
...
dispatch_async(dispatch_get_main_queue(), ^{
if (succ) {
[expectation fulfill];
}
else {
XCTFail(@"...");
}
});
});
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
XCTFail(@"...");
}];
数字比较的问题
由于浮点数储存的机制,浮点数和对应的字符串比较偶尔会出现一些奇奇怪怪的问题,@"3.5".floatValue == 3.5 会返回 false,这里推荐使用 NSNumberFormatter
来处理
第三方框架
推荐使用Expecta,SDWebImage 的 unitTests 也使用的此框架。
网友评论