XCTest单元测试

1.基础知识

什么是单元测试:
单元测试是开发者编写的一小段代码,用于检验被测代码中的一个很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。
单元测试在程序里面可以理解一个模块一个方法,在每个可能存在的模块都进行测试,确保每个模块都没有问题,从而提高整体程序的质量。

XCTest使用方法

  1. 测试用例被分到继承 XCTestCase 的不同子类中去
    每个以 test 为开头的方法都是一个测试用例。
    自定义类

  2. 命名

    我们可以用比如testThatIt将重点转移到期望的结果上的测试用例
    test + 要测试的方法和类名,比如像 testHTTPRequest来测试一些特定类型的
    我们还可以采用category 来将它们按主题分类

  3. Given / When / Then
    根据 Given-When-Then 模式来组织我们的测试用例
    这三部分分别指:Given:通过创建模型对象或将被测试的系统设置到指定的状态,来设定测试环境
    When:包含了我们要测试的代码
    Then:检查我们行为的结果,这里通常为一些断言

  4. 可重用代码
    整理所有有用的代码片段,并将它们加入到一个公共类中,为所有的测试用例服务,这个公共类非常实用。这个测试基础类能够运行自己的 -setUp 和 -tearDown 方法来配置环境。我们大部分情况用它来初始化测试用的 Core Data 栈,来重新设置我们的具有确定性的 NSUUID (这是那些可以让调试简单得多的一些东西中的一个),并且设置一些后台的魔法来简化异步测试。

  5. Mock
    我们使用的Mock框架是OCMock,mock 是一个在方法调用时返回标准答案的对象

XCTest使用范畴

Apple在Xcode 6中新增了UnitTest
XCTest测试范畴:
基本逻辑测试处理测试
异步加载数据测试
数据mock测试

XCTest常用基本测试工具
XCTest常用的一些判断工具都是以XCT开头的

补充:代码覆盖率:代码覆盖率 = 实际执行的代码行数 / 整个工程总代码行数,直白来讲就是这样一个数值; Xcode7以后Apple推出了更为人性化的工具来统计代码覆盖率,使用简介传送门

用XCTest完成的最简单的测试Demo

  1. 创建项目时勾选

    新建项目时勾选

  2. 进入项目

    注意路径

    进入到这个类,setUp是每个测试方法调用前执行,tearDown是每个测试方法调用后执行。testExample是测试方法,和我们新建的没有差别。不过测试方法必须testXXX的格式,且不能有参数,不然不会识别为测试方法。测试方法的执行顺序是字典序排序。
    uinitTest5

  3. 测试用例

    点击上图箭头的开始图标即可测试这个文件中测试方法
    在测试方法前也有开始图标,点击即可测试这个方法
    开始测试

    按快捷键Command + U进行单元测试,这个快捷键是全部测试

    测试方法出错
    这里我们断言a=0是错误的所以没有通过

  4. XCTest常见的断言

    XCTFail(format…) 生成一个失败的测试;
    XCTAssertNil(a1, format...)为空判断,a1为空时通过,反之不通过;
    XCTAssertNotNil(a1, format…)不为空判断,a1不为空时通过,反之不通过;
    XCTAssert(expression, format...)当expression求值为TRUE时通过;
    XCTAssertTrue(expression, format...)当expression求值为TRUE时通过;
    XCTAssertFalse(expression, format...)当expression求值为False时通过;
    XCTAssertEqualObjects(a1, a2, format...)判断相等,[a1 isEqual:a2]值为TRUE时通过,其中一个不为空时,不通过;
    XCTAssertNotEqualObjects(a1, a2, format...)判断不等,[a1 isEqual:a2]值为False时通过;
    XCTAssertEqual(a1, a2, format...)判断相等(当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以);
    XCTAssertNotEqual(a1, a2, format...)判断不等(当a1和a2是 C语言标量、结构体或联合体时使用);
    XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)判断相等,(double或float类型)提供一个误差范围,当在误差范围(+/-accuracy)以内相等时通过测试;
    XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...) 判断不等,(double或float类型)提供一个误差范围,当在误差范围以内不等时通过测试;
    XCTAssertThrows(expression, format...)异常测试,当expression发生异常时通过;反之不通过;(很变态) XCTAssertThrowsSpecific(expression, specificException, format...) 异常测试,当expression发生specificException异常时通过;反之发生其他异常或不发生异常均不通过;
    XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)异常测试,当expression发生具体异常、具体异常名称的异常时通过测试,反之不通过;
    XCTAssertNoThrow(expression, format…)异常测试,当expression没有发生异常时通过测试;
    XCTAssertNoThrowSpecific(expression, specificException, format...)异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过;
    XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过

    注意: 特别注意下XCTAssertEqualObjects和XCTAssertEqual。
    XCTAssertEqualObjects(a1, a2, format...)的判断条件是[a1 isEqual:a2]是否返回一个YES。XCTAssertEqual(a1, a2, format...)的判断条件是a1 == a2是否返回一个YES。对于后者,如果a1和a2都是基本数据类型变量,那么只有a1 == a2才会返回YES
    XCAssertEqual(a1, a2, format...)当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以

  5. 性能测试用例的实现

1. XCTest异步测试

XCTestExpression类带入了异步测试,我们可以可以等待指定长度的时间,一直到某些条件符合的时候在开始测试。而不用再写很多的GCD代码控制
我们可以定义这样的宏

#define WAIT do {\
[self expectationForNotification:@"RSBaseTest" object:nil handler:nil];\
[self waitForExpectationsWithTimeout:30 handler:nil];\
} while (0);

#define NOTIFY \
[[NSNotificationCenter defaultCenter]postNotificationName:@"RSBaseTest" object:nil];

异步网络测试用例

-(void)testRequest{
    // 1.获得请求管理者
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
    mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",nil];
    // 2.发送GET请求
    [mgr GET:@"http://www.weather.com.cn/adat/sk/101110101.html" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"responseObject:%@",responseObject);
        XCTAssertNotNil(responseObject, @"返回出错");
        self.stAlertView = [[STAlertView alloc]initWithTitle:@"验证码" message:nil textFieldHint:@"请输入手机验证码" textFieldValue:nil cancelButtonTitle:@"取消" otherButtonTitle:@"确定" cancelButtonBlock:^{
            //点击取消返回后执行
            [self testAlertViewCancel];
            NOTIFY //继续执行
        } otherButtonBlock:^(NSString *b) {
            //点击确定后执行
            [self alertViewComfirm:b];
            NOTIFY //继续执行
        }];
        [self.stAlertView show];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"error:%@",error);
        XCTAssertNil(error, @"请求出错");
        NOTIFY //继续执行
    }];
    WAIT  //暂停
}