【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

iOS 开发中的单元测试(一)

  • 2013-06-05
  • 本文字数:3412 字

    阅读完需:约 11 分钟

导读:本文不讨论单元测试是什么,或者它之于一个工程的利弊,我认为单元测试是一个开发者保证产出代码质量的有效工具。本文从使用者的角度对比当下比较流行的两款单元测试框架,给大家提供一些选用建议。如果你还不甚了解单元测试在工程中所起到的作用,或者还不知道TDD的开发模式,可参考: Test-Driven Development Unit Testing

本文对比两个 iOS 开发中常见的单元测试框架:OCUnit,被官方集成进 XCode 4.x 版本中;GHUnit,被推荐最多的测试框架,带 GUI 界面。初窥两款测试框架非常相似,而上手使用就会发现其中的区别。细节上的区别使两款框架在不同角度各有优劣。

OCUnit

OCUnit 是 XCode 4.x 集成的单元测试框架,OCUnit 中的测试分为两类,一类称为 Logic Tests,另一类称为 Application Tests。Logic Tests 更倾向于所谓的白盒测试,用于测试工程中较细节的逻辑;Application Tests 更倾向于黑盒测试,或接口测试,用于测试直接与用户交互的接口。

• 添加单元测试

OCUnit 是 XCode 集成的,所以其与工程的结合理应是最好的,添加到工程中的成本也理应最低。使用 XCode 创建新工程的流程中就有一个“Include Unit Tests”的选项(如图 1),新的工程就会自动生成一个 Logic Tests。

向已存在的工程中添加 OCUnit Logic Tests 也不复杂,只需要添加一个类型为:“Cocoa Touch Unit Testing Bundle”的 Target 即可(如图 2)。

图 2,向已存在的工程中添加 OCUnit 测试

向已有工程中添加一个测试 Target 时,XCode 会自动生成一个 Scheme,运行单元测试用例和 Build 原工程需要切换不同的 Scheme。如果认为切换 Scheme 非常麻烦,也可以在添加 Target 之前,在“Manage Scheme”菜单中取消“Autocreate schemes”(如图 3)。

图 3,添加 Target 不创建 Scheme

Application Tests 要基于 Logic Tests 做一些修改。一般来说一个工程既需要 Logic Tests 也需要 Application Tests,所以建议按照上述方法添加一个单独的 Target,然后执行以下操作(如图 4):

1. 在 Build Settings 中搜索“bundle loader”,设置为:$(BUILT_PRODUCTS_DIR)/APP_NAME.app/APP_NAME(APP_NAME 是应用名)

2. 再搜索“test host”,设置为:$(BUNDLE_LOADER)

3. 在 Build Phases-Target Dependencies 中添加依赖,选择主程序 Target

图 4,添加一个 Application Tests

• 创建测试用例

OCUnit 的测试用例最常用的方法有三个

1. - (void)setUp:每个 test 方法执行前调用

2. - (void)tearDown:每个 test 方法执行后调用

3. - (void)testXXX:命名为 XXX 的测试方法

添加 Target 之时 XCode 已经自动创建了一个测试用例类:UnitTestDemoTests,其中 UnitTestDemo 是工程的名字,该类中已经包含了 setUp,tearDown 和 testExample 三个方法。

通过 command+n,选择“Objective-C test case class”创建一个新的测试用例类(如图 5)。通过 XCode 创建的测试用例类是一个继承自 SenTestCase(OCUnit 由 SEN:TE 公司开发,因此基类命名为 SenTestCase)的空类,需要模仿 UnitTestDemoTests 编写测试方法。

图 5,创建一个测试用例类

开发者可以自己实现无返回值,且命名规则为 testXXX 的实例方法,并使用框架提供的大量断言方法。

Logic Tests 与 Application Tests 的区别主要在 setUp 方法,Logic Tests 只需在 setUp 方法中初始化一些测试数据,而 Application Tests 需要在 setUp 方法中获取主应用的 AppDelegate,供 test 方法调用。

值得注意的是,OCUnit 的 test bundle 是侵入主应用的,因此在使用过程中要十分注意,不要让单元测试的资源覆盖主应用资源,造成诡异的 Bug。

• 运行测试

由于 OCUnit 是集成在 XCode 中的框架,因此在 XCode 中运行也比较方便。切换到单元测试的 scheme(如果与工程共用 scheme 则无需切换),Product->Test(或直接使用快捷键 command+u),框架会自动查找所有工程中 SenTestCase 的子类,运行其中全部命名类似 testXXX 的无返回值方法。

• 测试反馈

OCUnit 的失败方法会通过 Console 和 XCode Issues 两个位置反馈,通过 XCode Issues 可以直接定位到出现错误的单元测试代码行。Issue 的提示信息就是在单元测试断言方法中定义的 description。

GHUnit

GHUnit 是一款 Objective-C 的测试框架,除了支持 iOS 工程还支持 OSX 的工程,但 OSX 不在本文的讨论范围。GHUnit 不同于 OCUnit,它提供了 GUI 界面来操作测试用例,而且也不区分 Logic Tests 和 Application Tests。

• 添加单元测试

与集成进 XCode 的 OCUnit 相比,GHUnit 的添加过程略显复杂。首先在上下载 GHUnit 的框架包,当前的 For iOS 的最新版本是 0.5.6,解压后是一个 GHUnitIOS.framework 的文件夹。

打开已经存在的工程,添加一个 EmptyApplication Target,并在新 Target 中添加刚刚下载的 GHUnitIOS.framework(如图 6、7)。

图 6,在新 Target 中添加 GHUnitIOS.framework

在 Build Phases 中添加非官方框架并不会把框架文件拷贝到工程目录,而是只做一个链接,所以建议在添加之前先把框架拷贝到工程目录下。

图 __7_,选择 __GHUnitIOS.framework_

接下来用相同的方法添加框架依赖的其他库:“QuartzCore.framework”。

在 Build Settings 中搜索“linker flags”,设置 Other Linker Flags - Debug - 添加一个支持全架构和全版本 SDK 的标示“-ObjC -all_load”(如图 8)。

图 __8_,设置 __linker flags_

删除 Tests Target 中的 AppDelegate(.h 和.m 一起删除)。修改 main 函数,支持 GHUnitIOS,导入 GHUnitIOSAppDelegate 代替原来的 AppDelegate,修改 UIApplicationMain 的参数(如图 9)。

图 __9_,修改 __main__ 函数 _

至此已经完成了 GHUnit 的添加,选择新建 Target 同时创建的 scheme,直接 Build and Run 即可在设备或 Simulator 中启动一个新的 App(如图 10),即该单元测试的 App。

图 __10_,单元测试 __App_

• 创建测试用例

创建 GHUnit 测试用例与创建 OCUnit 测试用例相似。

新建一个 Objective-C Class 文件,继承自 GHTestCase,在 XCode 生成的.h 文件中不会导入 GHUnit.h 文件,需要开发者自行导入“#import <GHUnitIOS/GHUnit.h>”。

GHUnit 框架提供断言方法比 OCUnit 更加丰富,开发用例也就可以做的更加细致,更有利查找 / 定位错误。

测试方法的命名规则与 OCUnit 一样,是以 test 开头的无返回值方法:- (void)testXXX。而常用的方法除了上述提到的 setUp 和 tearDown,GHUnit 还提供了 setUpClass 和 tearDownClass 两个方法,在该用例运行前和结束后调用。另外,刚刚提到 GHUnit 不区分 Logic Tests 和 Application Tests,所以在 setUp 和 tearDown 方法中也就不存在设置的区分。

• 运行测试

运行 GHUnit 需要分两步,首先编译并安装单元测试 App 到设备或 Simulator 里(如图 11),创建了两个用例,每个用例中分别有一个方法。

图 __11_,两个用例的 __GHUnit App_

在 App 中可以通过点击右上角的 Run 按钮运行全部用例,框架会查找所有以 testXXX 命名的无返回值方法,并执行。或点击 TableView 中的某个 Cell 运行单独的测试方法。

• 测试反馈

断言失败测试未通过的方法在 App 中会标记为红色,并给出每一个方法的运行时间。在 Console 中会打印出详细的出错信息,包括:异常类型,出错文件,位置,以及断言方法中指定的出错原因。更重要的是,出错时的程序堆栈内容(如图 12)。

图 __12_,未通过测试的方法,_Console__ 中的内容

GHUnit 通过 Console 中的内容给开发者提供帮助,可以快速定位程序出错的位置,这一点比 OCUnit 做的要好。

总结

GHUnit 在安装上确实显得有些麻烦,无法跟集成在 XCode 里的 OCUnit 相比。 但从开发者的角度讲,我更喜欢 GHUnit 带来的体验,GUI 的操作界面可以脱离 IDE 单独运行,支持运行单一测试方法和运行全部用例的,打印出错堆栈可以更快定位到问题所在。

本文简单介绍了两款框架的安装与入门,可以初步了解其各自特点,在接下来的文章中将会更加详细的介绍如何使用框架进行单元测试,以及框架中的一些高级功能。此外,后续还将向大家介绍另外的与这两款框架区别更加明显的单元测试框架。

作者简介:

高嘉峻(微博: @gaosboy ),SegmentFault.com 联合创始人,杭州 iOS 开发者沙龙发起人,资深 iOS 开发者。


感谢李永伦对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2013-06-05 08:4732216

评论

发布
暂无评论
发现更多内容

go语言逆向技术之---常量字符串解密

sofiya

“云上生长”网络研讨会|使用 GPU 和 VPU 等异构硬件加速视频转码

青云技术社区

gpu 音视频

pe文件签名信息检测技术

科技怪咖

二进制SCA检测工具---技术短板及应对措施

科技怪咖

从检测角度思考美燃油管道商遭勒索攻击事件

科技怪咖

设计模式的艺术 第十五章代理设计模式练习(设计一款基于C/S的网络图片查看器,用户只需在图片查看器中输入网页URL,程序将自动将网页所有图片下载到本地。)

代廉洁

设计模式的艺术

云原生游戏第 2 讲:OpenKruiseGame 设计理念详解

阿里巴巴云原生

阿里云 容器 云原生 游戏 OpenKruiseGame

骞云获得阿里云首批产品生态集成认证,携手阿里云共建新合作

阿里巴巴云原生

阿里云 云原生 加速器 伙伴

移动应用中的第三方SDK隐私合规检测

sofiya

CVE-2022-0847 DirtyPipe漏洞分析

sofiya

go语言逆向技术之---恢复函数名称算法

科技怪咖

Carina 全新版本 v0.11.0 上线!重磅升级不可错过

BoCloud博云

云计算 云原生 #开源

宿舍全屋智能开发指南

OpenHarmony开发者

OpenHarmony

java培训程序员靠技术来延长自己的职业周期

小谷哥

云原生(三十二) | Kubernetes篇之平台存储系统介绍

Lansonli

云原生 9月月更

阿里云视觉智能开放平台9月特惠来袭

夏夜许游

技术分享| 调度平台的好助手-快对讲

anyRTC开发者

音视频 调度 实时消息 快对讲 视频对讲

新思科技解析Repo Jacking依赖仓库劫持如何影响供应链安全

InfoQ_434670063458

漏洞 新思科技 软件供应链 Repo Jacking

Web漏洞靶场搭建(OWASP Benchmark)

sofiya

软件测试 | 接口自动化测试,如何实现多套环境的自动化测试?

测试人

软件测试 自动化测试 接口测试 测试开发

区块链入局,远程医疗这回“靠谱”了!

旺链科技

区块链 产业区块链 远程医疗 企业号九月金秋榜

程序员“反内卷”大法——和无效加班说再见!

博文视点Broadview

2022年中国证券行业智能投顾专题分析

易观分析

金融 证券

漫谈软件成分分析(SCA)安全测试技术

科技怪咖

MobTech 短信验证REST API

MobTech袤博科技

REST API MobTech袤博科技

云速ERP(WeLink认证版)上线,加速中小微企业数字化经营创新

IT资讯搬运工

人工智能’

MobTech SMSSDK iOS端快速集成指南

MobTech袤博科技

ios sdk

iOS如何实现验证码登录丨MobTech

MobTech袤博科技

ios xcode

【云原生 | Docker】部署 Django & Nginx & Gunicorn

计算机魔术师

8月月更

基于深度学习下的航空领域真空羽流解决方案

蓝海大脑GPU

pe文件签名信息检测技术

sofiya

iOS开发中的单元测试(一)_Android/iOS_高嘉峻_InfoQ精选文章