iOS —— 单元测试(一)

目录

一、简介

单元测试是指开发者编写代码,去验证被测代码是否正确的一种手段,其实就是用代码去检测代码。合理的利用单元测试可以提高软件的质量。

二、苹果自带的XCTest

1.创建我们的工程,勾选 Include Unit Tests
在这里插入图片描述

2.创建单元测试类
在这里插入图片描述
3.命名和继承的父类
在这里插入图片描述

UserInfoModelTest.m中的代码:

+ (void)setUp {
    [super setUp];
}

+ (void)tearDown {
    [super tearDown];
}

// 单元测试开始前调用
- (void)setUp {
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

// 单元测试结束前调用
- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
}

// 测试代码可以写到以test开头的方法中 并且test开头的方法左边会生成一个菱形图标,点击即可运行检测当前test方法内的代码
- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
    
    // 测试的基本结构,三段式
    // 1、Given 创造测试条件。数据初始化的对象,值。可以使用 OCMock 三方库。
    UserInfoModel *userInfoModel = [UserInfoModel new];
    
    // 2、When 测试方法的参数
    userInfoModel.age = @10;   // 模拟合法年龄( 0 < age < 80 认为是合法年龄)
    
    // 3、Then 断言,是否符合预期
    XCTAssert(userInfoModel.age.integerValue > 0, "姓名大于0 - 合法");
    XCTAssert(userInfoModel.age.integerValue < 80, "姓名小于80 - 合法");
}

// 测试性能
- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}

测试方法会以 -(void)testXXX方式命名。
我们一起看一下方法的调用顺序,可以使用快捷键 command + U

  1. 先调用 + (void)setUp方法,加载我们的测试类
  2. 调用- (void)setUp,单元测试开始前调
  3. 调用- (void)testExample,测试代码可以写到以test开头的方法中 并且test开头的方法左边会生成一个菱形图标,点击即可运行检测当前test方法内的代码;
  4. 调用- (void)tearDown,单元测试结束前调用;
  5. 调用- (void)setUp,重置对象等的信息,继续测试
  6. 调用- (void)testPerformanceExample,测试性能
  7. 调用- (void)tearDown
  8. 最后调用 + (void)tearDown

我们可以看到 - (void)setUp- (void)tearDown会重复调用,分别表示测试开始重置对象或数据,测试结束。

另外,测试代码可以写到以 test开头的方法中 并且 test开头的方法左边会生成一个菱形图标(如下图),点击即可运行检测当前test方法内的代码。
菱形图标

test方法中的代码一般为三段式结构,如上代码。

下面我们模拟对 UserInfoMode类中的 age 属性进行测试,具体实现可以看上面的代码。

测试通过
测试未通过
我们主要是设置一些 断言,来判断代码是否符合我们的预期,是否符合逻辑。

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没有发生具体异常、具体异常名称的异常时通过测试,反之不通过

以上是XCTest的基本用法,下面我们说一下- (void)testPerformanceExample性能测试。将要测试执行时间的代码放到 block 块内

// 测试性能
- (void)testPerformanceExample {
    NSLog(@"%s", __func__);
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
        NSMutableArray *testArray = [[NSMutableArray alloc] init];
        for (int i = 0; i < 10000; i ++) {
            NSObject *obj = [[NSObject alloc] init];
            [testArray addObject:obj];
        }
    }];
}

控制台输出结果:

Test Case '-[UserInfoModelTest testPerformanceExample]' measured [Time, seconds] average: 0.015, relative standard deviation: 61.727%, values: [0.003263, 0.022181, 0.019327, 0.002817, 0.023823, 0.004887, 0.026164, 0.022138, 0.004508, 0.021344], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100

从这里我们可以获知在一个for循环重复的代码,程序会运行10次,取一个平均运行时间值,average: 0.015这个就是平均时间0.015秒。

现在我们知道了测量一个函数的运行时间,到底这个函数效率高不高可以使用testPerformanceExample方法,但是在这之前我们怎么测试函数性能呢?我们可以使用NSTimeInterval来做,根据时间差的打印来分析,具体用法如下代码:

// 测试性能
- (void)testPerformanceExample {
    [self measureBlock:^{
    	// CACurrentMediaTime() 是手机从开机一直到当前所经过的秒数。
        NSTimeInterval startTime = CACurrentMediaTime();
        NSMutableArray * mutArray = [[NSMutableArray alloc] init];
        for (int i = 0; i < 10000; i++) {
            NSObject * object = [[NSObject alloc] init];
            [mutArray addObject:object];
        }
        NSLog(@"耗时:%f",CACurrentMediaTime() - startTime);
    }];
}

输出结果:

2019-02-13 12:49:36.298823+0800 CocoapodsDemo[7824:2125978] 耗时:0.031548
2019-02-13 12:49:36.335230+0800 CocoapodsDemo[7824:2125978] 耗时:0.033513
2019-02-13 12:49:36.363585+0800 CocoapodsDemo[7824:2125978] 耗时:0.001930
2019-02-13 12:49:36.382447+0800 CocoapodsDemo[7824:2125978] 耗时:0.017103
2019-02-13 12:49:36.401863+0800 CocoapodsDemo[7824:2125978] 耗时:0.017622
2019-02-13 12:49:36.421803+0800 CocoapodsDemo[7824:2125978] 耗时:0.017795
2019-02-13 12:49:36.444744+0800 CocoapodsDemo[7824:2125978] 耗时:0.020235
2019-02-13 12:49:36.466671+0800 CocoapodsDemo[7824:2125978] 耗时:0.019422
2019-02-13 12:49:36.487286+0800 CocoapodsDemo[7824:2125978] 耗时:0.018172
2019-02-13 12:49:36.506918+0800 CocoapodsDemo[7824:2125978] 耗时:0.001468

参考:
浅谈iOS单元测试

猜你喜欢

转载自blog.csdn.net/weixin_41463971/article/details/87179359