目录
前言:
在iOS开发中,单元测试是不可或缺的一部分,它可以帮助开发者在编写代码时,对应用程序的各个部分进行测试,以确保代码的正确性和可靠性。OCMock是一个常用的OC语言测试框架,可以模拟对象行为、设置预期等操作,方便测试人员进行各种场景的测试。
一、单元测试
1.1 单元测试的必要性
测试驱动开发并不是一个很新鲜的概念了。在日常开发中,很多时候需要测试,但是这种输出是必须在点击一系列按钮之后才能在屏幕上显示出来的东西。测试的时候,往往是用模拟器一次一次的从头开始启动 app,然后定位到自己所在模块的程序,做一系列的点击操作,然后查看结果是否符合自己预期。
这种行为无疑是对时间的巨大浪费。于是有很多资深工程师们发现,我们是可以在代码中构造一个类似的场景,然后在代码中调用我们之前想要检查的代码,并将运行结果和设想结果在程序中进行比较,如果一致,则说明我们的代码没有问题,由此就产生了单元测试。
1.2 单元测试的目的
单元测试的主要目的是发现模块内部逻辑、语法、算法和功能错误。
单元测试主要是基于白盒测试验证以下问题:
- 验证代码与设计相符度。
- 发现设计和需求中存在错误。
- 发现在编码过程中引入的错误。
单元测试关注的重点有以下部分:
独立路径-对于基本执行路径和循环进行测试,可能的错误有:
- 不同数据类型的比较。
- “差1错”,即可能多循环或少循环一次。
- 错误或不可能的终止条件。
- 不适当的修改了循环变量。
局部数据结构-单元的局部数据结构是最常见的错误来源,应设计测试用例以检查可能的错误:
- 不一致的数据类型。
- 检查不正确或不一致的数据类型。
错误处理-比较完善的单元设计要能预见出错的条件,并设置适当的错误处理,以便在程序出错时,能对错误重新做安排,保证期逻辑上的正确性:
- 出错的描述难以理解。
- 显示的错误与实际的错误不符。
- 对错误条件的处理不正确。
边界条件-边界上出现错误是最常见的错误现象:
- 取最大最小值发生错误。
- 控制流中的大于、小于这些比较值常出现错误。
单元接口-接口实际上就是输入和输出对应关系的集合,要对单元进行动态测试无非就是给这个单元一个输入,然后检查输出是否和预期一致。如果数据不能正常输入和输出,单元测试就无从谈起,因此需要对单元接口进行如下的测试:
- 被测单元的输入、输出在个数、属性、顺序是否和详细设计中的描述一致。
- 是否修改了只做输入用的形式参数。
- 约束条件是否通过形式参数来传送。
1.3 单元测试依赖的两个主要框架
OCUnit(即用 XCTest 进行测试)其实就是苹果自带的测试框架,主要是断言使用,由于使用简单本次文章不过多介绍。
OCMock主要功能是模拟某个方法或者属性的返回值,你可能会疑惑为什么要这样做?使用模型生成的模型对象,再传进去不就可以了?答案是可以的,但是有特殊的情况,比如一些不容易构造或不容易获取的对象,此时你可以创建一个虚拟的对象来完成测试。实现思想是根据要mock的对象的class来创建一个对应的对象,并且设置好该对象的属性和调用预定方法后的动作(例如返回一个值,调用代码块,发送消息等等),然后将其记录到一个数组中,接下来开发者主动调用该方法,最后做一个verify(验证),从而判断该方法是否被调用,或者调用过程中是否抛出异常等。在单元测试开发中使用更多难点的也是对OCMock的使用方式不明确,本次文章主要讲的就是这个 OCMock 的集成和使用方法。
二、OCMock 的集成与使用
2.1 OCMock 的集成方式
项目集成 OCMock 第三方库,这个使用 pod 工具直接安装OCMock框架即可。若使用 iBiu 工具安装 OCMock 库需在 podfile 文件同级创建 Podfile.custom。
使用普通的 pod 文件相同格式添加 OCmock 如下:
source 'https://github.com/CocoaPods/Specs.git'
pod 'OCMock'
2.2 OCMock 的使用方法
(一)置换方法(存根):告诉 mock 对象,当 someMethod 被调用,返回什么值
调用方式:
d jalopy = [OCMock mockForClass[Car class]];
OCMStub([jalopy goFaster:[OCMArg any] units:@"kph"]).andReturn(@"75kph");
使用场景:
1. 验证 A 方法时,A 方法内部使用 B 方法的返回值但是 B 方法内部逻辑比较复杂,这时