iOS unit test 杂记

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 也使用的此框架。

你可能感兴趣的:(iOS unit test 杂记)