iOS单元测试

什么是单元测试

单元测试:是对最小单元(方法、函数)的验证性测试。一般来说,单元测试不需要依赖外部环境、网络环境、数据库环境。

UI 测试:结合页面元素和交互流程,对应用业务进行测试。

单元测试原则

快速(Fast):测试应该能快速运行。

独立(Independent):测试应该相互独立,不能有依赖。

可重复(Repeatable):测试应当可在任何环境重复通过。包括无网络的环境。

自足验证(Self-Validating):测试应该有布尔值输出。

及时(Timely):测试应及时编写。单元测试应该恰好在使其通过的代码之前编写。如果业务代码更改,测试代码也应该考虑是否随其变动

哪些代码需要单元测试

模块备注
算法相关优先最高,保证算法正确性,避免后期改动造成错误
对外提供的 Router保证外部调整和唤起正常
业务逻辑自行创建测试数据和条件参数测试
网络数据处理通过 Mock 处理测试
ViewController通过 UI 测试
ViewModel/xxxUtil/xxxManager
全局方法、类方法
本地json/配置文件app启动或者依赖资源,保证其可访问和完整性

以下部分不建议添加单元测试

Model 层、具体网络请求

为什么要做单元测试

  1. 保证最小单元的正确性
  2. 检查函数是否符合预期(要达到什么目的)
  3. 验证边界条件(最大/最小、最坏/最好、最?/最?情况下是否满足)
  4. 异常情况考虑
  5. 保证重构顺利进行(重构了是否满足)

UI测试,更注重保证回归线和业务正确性。

如何做单元测试

单元测试原则

单元测试开发主要是基于以下三个要素:

**Given(条件):**配置测试的初始状态,比如造一些数据、mock一些对象等,这里我们可能需要OCMock这个库的辅助。

**When(测试条件):**对要测试的目标执行代码,调用你要测试的方法

**Then(结果检查):**对测试结果进行断言(成功 or 失败),对于结果做一个预判,并且通过编译来判断你的预判是否正确

- (void)testGetNameSpaceFromUUID{
NSDictionary *data = 0(0"aaa":@fo"type":@(@"namespace":@"bbb"}));  // Given
NSString *nameSpace = [SCSCartInfoParser getNameSpaceFromUUID:@"aaa" withData:data]; // When
XCTAssert ([nameSpace isEqualToString:@"bbb"]); // Then
}

不要对私有方法进行测试(如果需要,请尝试拆离到单独的类)

UI 测试

UI测试更加关注交互和业务,用代码去模拟用户的行为。

比如通过按钮的sendActionsForControlEvents:方法模拟点击,通过代理方法实现查看点击 cell 时间是否符合预期等。

单元测试技术

由于 XCTest 适合简单情况,存在阅读性差的问题,所以同时引入 Kiwi 框架,在复杂类和测试中可使用 Kiwi 来编写单元测试。

XCTest

XCTest是自带的简单单元测试技术。

示例代码:

- (void)testRemoveTailOfZero {
    NSString *givenStr1 = @"0.0023002300";
    NSString *givenStr2 = @"000043003400";
    NSString *givenStr3 = @"9.00";
    NSString *givenStr4 = @"100.0";
   
    XCTAssertTrue([[givenStr1 removeTailOfZero] isEqualToString:@"0.00230023"], @"移除末尾为0和.错误");
    XCTAssertTrue([[givenStr2 removeTailOfZero] isEqualToString:@"000043003400"], @"移除末尾为0和.错误");
    XCTAssertTrue([[givenStr3 removeTailOfZero] isEqualToString:@"9"], @"移除末尾为0和.错误");
    XCTAssertTrue([[givenStr4 removeTailOfZero] isEqualToString:@"100"], @"移除末尾为0和.错误");
}

Kiwi

Kiwi是一个iOS平台十分好用的行为驱动开发(Behavior Driven Development,以下简称BDD)的测试框架,有着非常漂亮的语法,可以写出结构性强,非常容易读懂的测试。

优点

  • 结构性强、可读性高
  • 支持 mock、stub
  • 支持参数捕获、异步测试

示例代码:

describe(@"NSString+Category", ^{
  context(@"去除小数点末尾0", ^{
        it(@"当0.0023002300时,应该去除后面两个0,即:0.00230023", ^{
            [[@"0.0023002300".removeTailOfZero should] equal:@"0.00230023"];
        });
        it(@"当000043003400时,整数保持不便", ^{
            [[@"000043003400".removeTailOfZero should] equal:@"000043003400"];
        });
        it(@"当9.00时,应该去除小数点后面两个0,即:9", ^{
            [[@"9.00".removeTailOfZero should] equal:@"9"];
        });
        it(@"当100.0时,应该去除小数点后面一个0,即:100", ^{
            [[@"100.0".removeTailOfZero should] equal:@"100"];
        });
    });
}

如过你打算使用 Kiwi,强烈建议你阅读以下教程:

TDD 的 iOS 开发初步以及 Kiwi 使用入门 – OneV

Kiwi 使用进阶 Mock, Stub, 参数捕获和异步测试 – OneV

stub

可以理解为测试桩,它能实现当特定的方法被调用时,返回一个指定的模拟值。如果你的测试用例需要一个伴生对象来提供一些数据,可以使用 stub 来取代数据源,在测试设置时可以指定返回每次一致的模拟数据。

spy

可以理解为侦查,它负责汇报情况,持续追踪什么方法被调用了,以及调用过程中传递了哪些参数。你能用它来实现测试断言,比如一个特定的方法是否被调用或者是否使用正确的参数调用,方法返回值。当你需要测试两个对象间的某些协议或者关系时会非常有用。

mock

与 spy 类似,但在使用上有些许不同。spy 追踪所有的方法调用,并在事后让你写断言,而 mock 通常需要你事先设定期望。你告诉它你期望发生什么,然后执行测试代码并验证最后的结果与事先定义的期望是否一致。

如何让代码更具备单元测试能力

按照 TTD 开发流程,应该先写测试用例,再编写组合业务代码。但是也存在待测试先行,在编写待测试代码时,我们应该遵循以下原则:

  1. 待测试的函数功能单一且明确
  2. 应该具有输入输出(以便测试环境 mock 和输出结果检查)
  3. 为了提高可测试性,应该将功能逻辑提取到单独的处理类中,而不是统一在 ViewController 中处理。
  4. 使用 BDD 思维来定义接口(思考一个对象的行为 (它的接口应该如何) 并且减少对实现的关注)

避免 ViewController 臃肿问题

传统 MVC 模式容易导致大量逻辑代码存在于 ViewContoller 中,大量私有方法导致无法进行单元测试。

对此,我们应该抽离中间件,用来处理数据和逻辑处理,通过中间件来进行单元测试,同时,使 ViewController 更加简洁和单一职责。

开启单元测试覆盖率

通过勾选 Xcode 的 CodeCoverage可以查看单元测试覆盖率和覆盖部分。

转图

查看 Build Settings

转图

转图

如果需要配合自动化,可以借助 XcodeCoverage 库导出覆盖率查看

单元测试持续集成

待完成

Appium 自动化测试

优点:可以多语言, 有图形化操作

缺点:配置复杂。

配置参考

踩坑

  • WebDriverAgent 项目直接编译运行 Appium 包内容目录(/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-webdriveragent)下的
  • 修改 bundId 后还报错,点击 runer 中 build settings 中搜索 facabook 修改对应 bundId

参考

XCTest – 官方文档

[S01E02]iOS 单元测试

iOS 单元测试和 UI测试教程–raywenderlich

英文教程,从理论到实践操作。

Github+Fastlane+Jenkins 的持续集成测试–raywenderlich

可测试性工程

WWDC17官方视频讲解,介绍我们应该够如果编写可测试的代码。

京东多端全流程交易解决方案阿波罗平台iOS单元测试实践

通过集成化工具 Bamboo 和 XcodeCoverage 查看测试覆盖率。如何写一个单元测试,OCMock 基本介绍和使用

TDD 的 iOS 开发初步以及 Kiwi 使用入门 – OneV

Kiwi 使用进阶 Mock, Stub, 参数捕获和异步测试 – OneV

王巍编写的对 Kiwi 框架的理解和使用,如何利用 Kiwi 中的 Mock和 stub。示例包含了对 Kiwi 和原始 XCTest 使用。

相关 Demo

  • Demo VVStack: 同时使用 Kiwi 和 XCTest 进行单元测试对比

  • PhotoData_Kiwi:将 objc.io 中测试相关的 Demo 使用 Kiwi 替换,详细描述对类初始化及各个公共方法的测试,以及使用 stub 和 mock 测试 Controller。

objc.io 中国 测试相关文章

行为驱动测试 – objc.io

对objc.io文章的翻译,其中的测试板块内容,包含基本测试理论,单元测试实际集成经验等内容,非常建议阅读。

iOS自动化测试 UITests

主要介绍对元素的操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值