iOS接口的单元测试
近期把一个业务复杂,功能繁多的库进行了拆分,实现了功能的单一性。代码重构告一段落,功能验证并且提测了,在QA测试阶段,终于闲下来把单元测试的代码也进行拆分与补充了。
现在就来聊聊iOS代码的单元测试。
单元测试本质上就是对我们写的代码接口进行执行,传入特定的参数,返回执行结果,然后对比结果与期望的值是否一致,确定功能是否执行正确。
单元测试流程
不同于其他语言,Objective-C可以通过苹果官方的编辑器XCode提供的XCTest框架很方便的进行测试,可以不需要额外的第三方框架进行基础的单元测试。而JavaScript语言(jest)、C语言(CUnit)等需要专门的库才能作测试。
现在,我们公司iOS开发属于组件化开发,各个组件的代码都是在一个独立的库,工程通过cocoapods
管理。这样有一个好处,就是每个库的功能单一,接口少,代码都是由特定的一个或者几个人员维护,开发人员对代码比较熟悉,单元测试都是可以对所有文件的接口进行覆盖测试,还可以通过Xcode直观的看到每个文件的测试覆盖率。在代码入库检视时,检视人把好单元测试的关,很容易推动他人对代码作单元测试,提高代码的质量。
下面讲一下我是如何作单元测试的
如何开始单元测试
每个组件库代码都是一个由cocoapods
管理的workspace
工程组织的,构建最终输出是一个个.a
- 创建一个target, 类型为 iOS Unit Testing Bundle
- 在target下创建一个文件,继承XCTTestCase, 编写单元测试代码
- 工程选中对应的test target, 设置 Target Dependencies, Link Binart with Libraries 为库的target
- 编译执行test target (快捷键 command + U)
每个测试用例的重复代码可以写在 setUp
/tearDown
方法里, 分别为公共前置代码编写、资源清理的处理。
异步接口测试
针对一些异步执行的接口, XCTest提供了XCTestExpectation
来实现。
由于项目代码不便提供,这边请允许我偷个懒, 从SDWebImage
库上摘录一些测试代码O(∩_∩)O哈哈~
在回调里面,根据传入的参数判断是否符合预期, 是则调用fullfil方法,否则调用报错。
添加文件测试
- 添加文件到test target
- 使用
bundleForClass:
获取正确的bundle,再访问bundle路径下的具体文件。
使用OCMock进行代码mock
对于复杂的对象,可能会有许多成员。但是这些成员是不容易获得的, 我们可以通过OCMock模拟该成员,对部分函数进行打桩,达到期待的结果。
OCMock是一个库, 通过 podfile 引入该库, 然后根据文档进行操作。 具体文档可以访问链接
使用OHHTTPStubs 对网络接口进行mock
有些接口需要访问网络才能返回正常的结果,可以使用OHHTTPStubs这个库对网络请求进行打桩,根据请求的request确定是否要进行打桩。
查看代码覆盖率
- 工程Edit Scheme -> Test -> Options -> Gather coverage for xxx
- 跑一遍单元测试, 查看结果
更多
一般的接口功能的单元测试,掌握以上部分就可以了。 如果还有性能的测试、或者UI的测试可以看官网文档。
更多查看苹果文档
感想
为工程添加单元测试, 我们可能需要对已有代码进行重构, 使之可以是可被测试的。 通过单元测试代码的运行,可以很容易发现隐藏的问题, 不会引入新问题。 单元测试是代码质量的一个可靠的保障手段,好的团队应该对其代码进行单元测试。当然这里有巨大的工作量,但是是值得的。 以为本次代码重构的经历而言, 设计占2/5, 写代码4/15, 单元测试大概1/3. 比例大概为 6:4:5。 单元测试还是花了许多时间,但中间也发现了一些问题, 这些问题在前面功能自测的时候并没有发现,代码检视过程中也没有发现,单元测试的时候发现了,不枉我花了时间啊O(∩_∩)O哈哈~。 单元测试算是一个迭代的过程吧, 也有一点一劳永逸的感觉。
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。