iOS 单元测试

很多开发者都听说过单元测试,但是在实际开发中我们却很少使用到单元测试,一般流程规范的大项目一般都会做单元测试,下面主要介绍 Xcode 自带的 XCTest 测试工具。

单元测试

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。如C语言中的一个函数,Java里的一个类等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

为什么要进行单元测试
  1. 如果你在一个庞大的工程里面加个了小功能 A ,一般每次都要把工程跑起来,然后到 A 处进行测试。或者如果我们仅仅是想测试一个接口的返回的参数,而这个接口又需要使用到现有工程中的很多参数。如果使用 单元测试的话,就不用每次都把整个工程跑起来,只需要跑你测试的部分就行。
  2. 我们可以使用单元测试测某个方法的耗时和性能,当然我们可以使用 Instrument 来做更专业的测试。 相对而言,单元测试更加方便。
  3. UI测试:模拟用户操作,进而从业务层面测试,快速定位 bug,提高产品稳定性。
iOS中常用的单元测试框架
  1. Kiwi:一个行为驱动开发(BDD)的测试框架
  2. Quick:GitHub 上 Star 最多的测试框架,支持 OC 和 Swift
  3. Appium:基于 Client – Server 的测试框架。App 相当于一个 Server,测试代码相当于 Client,通过发送 JSON 来操作 App,测试语言可以是任意的,支持 android 和 iOS。混合开发模式常用。
  4. XCTest:XCode 自带的测试框架,同时支持单元测试和UI测试。
新建测试 Target 及测试类

创建单元测试和UI测试
在这里插入图片描述
新建测试类,注意:

  1. 新建的单元测试类必须继承自 XCTestCase,其中有3个重要方法, setUp ,tearDown,measureBlock
  2. 该类中以 test 开头且 void 返回类型的方法都会变成单元测试用例方法
    在这里插入图片描述
// 此方法每次测试前调用
 (void)setUp {
    [super 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.
    [super tearDown];
}
- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
}
// 性能测试方法,通过测试block中方法执行的时间,比对设定的标准值和偏差觉得是否可以通过测试
- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}
常用断言
 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没有发生具体异常、具体异常名称的异常时通过测试,反之不通过;
 
功能测试
- (void)testNumEqual {
    
    NSInteger result = 2 * 3;
    NSInteger expect = 6;
    
    XCTAssertEqual(result, expect, @"结果和预期不相等");
}
性能测试
- (void)testPerformanceExample {
    // This is an example of a performance test case.
    NSLog(@"性能测试");
    // 用来分析代码执行的时间(会执行10次),log会打印在 console 里,同时本地也会有一份日志
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
        
        for (NSInteger index = 0; index < 10000; index ++){
            
            NSLog(@"%ld",index);
        }
            
    }];
}

基准线和偏差是可以设置的,如果偏差10%,只要平均值在基准线的偏差10%都是可以通过的测试的。但是如果设置如果我们把baseline为1,偏差10%,那测试会失败,因为不满足条件。
在这里插入图片描述

异步测试
/// 期望
- (void)testAsynExample {
    XCTestExpectation *exp = [self expectationWithDescription:@"这里可以是操作出错的原因描述。"];
    NSOperationQueue * queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        // 模拟这个异步操作需要2秒后才能获取结果,比如一个异步网络请求
        sleep(2);
        // 模拟获取的异步操作后,获取结果,判断异步方法的结果是否符合预期
        NSString *result = @"dddd";
        NSString *expect = @"dddd";
        XCTAssertEqual(result, expect);
        // 如果断言没问题,就调用fulfill宣布测试满足
        [exp fulfill];
    }];
    
    //设置延迟多少秒后,如果没有满足测试条件就报错
    [self waitForExpectationsWithTimeout:3 handler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"Timeout Error: %@", error);
        }
    }];

}

异步测试除了使用 expectationWithDescription以外,还可以使用 expectationForPredicate 和 expectationForNotification。

UI测试
- (void)testLogin {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    // XCUIElement 这是 UI 元素的代理。元素都有类型和唯一标识。可以结合使用来找到元素在哪里,如当前界面上的一个输入框
    XCUIElementQuery *textFields = app.textFields;
    XCUIElement *usernameTextField = textFields[@"username:"];
    [usernameTextField tap];
    [usernameTextField typeText:@"Andy"];
    XCUIElement *passwordTextField = app.textFields[@"password:"];
    [passwordTextField tap];
    [passwordTextField typeText:@"123456"];

    //
    [app.buttons[@"login"] tap];

    // 登录成功后的控制器的title为用户名,只需判断控制器的title时候一样便可判断登录是否成功
    NSLog(@"title is %@",app.navigationBars.element.identifier);
   XCTAssertEqualObjects(app.navigationBars.element.identifier, @"Andy");

}

XCUIElement 和 XCUIElementQuery 是UI测试的两个核心类。

Coverage(代码覆盖率)

代码覆盖是LLVM提供的的测试选项。 当您启用代码覆盖时,LLVM将根据调用方法和函数的频率,对代码收集覆盖数据。 代码覆盖选项可以收集数据以报告正确性和性能的测试,无论是单元测试还是UI测试。

命令行测试

如果你有development-enabled设备插入,你可以按照名称或 id 调用他们。例如,如果你有一个名为”Development iPod touch”的 iPod 设备连接了测试的代码,可以使用下面的命令来测试代码 > xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination 'platform=iOS,name=Development iPod touch

测试也可以在 iOS模拟器上运行。使用模拟器可以应对不同的外形因素和操作系统版本。例如> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination ‘platform=iOS Simulator,name=iPhone,OS=8.0’

-destination 参数可以被连接在一起,这样你只需使用一个命令,就可以跨目标进行指定集成共享方案。例如,下面的命令把之前的三个例子合并到一个命令中。

> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp
-destination 'platform=OS X,arch=x86_64'
-destination 'platform=iOS,name=Development iPod touch'
-destination 'platform=iOS Simulator,name=iPhone,0S=7.0'

参考:

  1. iOS 单元测试之XCTest详解
  2. iOS单元测试详解
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值