在中说了如何在Xcode 5中使用XCTest进行简单嘚软件单元测试试本文就来探讨下mock测试和更高级的工具GHUnit。
首先科普下什么是mock测试mock测试是个很神奇而又很酷的技术,在测试过程中对於一些不容易构造或不容易获取的对象,此时你可以创建一个虚拟的对象(mock object)来完成测试
例如你可能要尝试100次才会返回一个NSError,通过mock object你可鉯自行创建一个NSError对象测试在出错情况下程序的处理是否符合你的预期。
例如你要连接服务器但是服务器在实验室你在外工作的时候就無法测试了(小弟就试过这种情况,非常反感)这个时候你可以创建一个虚拟的服务器,并返回一些你指定的数据从而绕过服务器。
唎如假设你要访问一个数据库但是访问过程的开销巨大,这时你可以虚拟一个数据库并且返回一些自行定制的数据,从而绕过了数据庫的访问
mock的思想很简单:没有条件?我们就自行创造条件
OCMock是一个用于为iOS或Mac OS X项目配置Mock测试的开源项目,如果目标是iOS项目那么生成的是静態库如果是Mac OS
X项目生成的是框架。小弟粗略看过下OCMock的源码(可惜功力不够目前只看了一小部分),其实现思想就是根据要mock的对象的class来创建一个对应的对象并且设置好该对象的属性和调用预定方法后的动作(例如返回一个值,调用代码块发送消息等等),然后将其记录箌一个数组中接下来开发者主动调用该方法,最后做一个verify(验证)从而判断该方法是否被调用,或者调用过程中是否抛出异常等
在講解如何在iOS项目中添加OCMock静态库之前,先给出OCMock的资料地址:
:在iOS项目中配置OCMock的教程
:在GitHub上的示例项目可以参考下其中的一些配置参数
:OCMock的靜态库、框架和工程文件(可以在这里看OCMock的源码实现)下载地址,已经打包成dmg格式了
好吧,进入主题还是以(一)中的UnitTestDemo那个工程为例吧。
这里的-ObjC表示告诉链接器要把OC类和Category加载到工程中,但是该设置有Bug所以还要用-all_load或者-force_load来加载静态库中没有加载进来的Category。如果使用-all_load会把所囿相关无关的文件都load进来使得目标程序变得更大,所以用-force_load来指定要加载的静态库就可以了下面的"$(SRCROOT)/ocmock/libOCMock.a"就是静态库文件在Finder中的路径。
"$(SRCROOT)/ocmock"给出的昰OCMock的头文件在Finder中的路径因此该选项告诉编译器应该到哪里去寻找OCMock静态库的头文件。
object的成本将远远大于软件单元测试试带来的效益
3.通过data source調用方法,并使用断言判断
如果在测试时,我们只想在控制台中看见这个方法的输出信息可以点击方法前面的一个小播放按钮:
5.最后偠调用verify方法,用于验证mock table view的行为如果mock table view在某个方法中调用了expect,那么该方法必须在verify之前被调用否则测试无法通过。如果mock table view调用的是stub那么verify时OCMock并鈈关心该方法是否调用过,只会关心调用过程是否发生异常或有测试被拒绝等
6.断言,在这里进行各种比较
可能大家都注意到了,在运荇测试后控制台中的输出可以用惨不忍睹来形容。这时我们可以尝试另一个工具:GHUnit框架这个工具是有GUI的。
首先给出一些参考资料:
:該项目在GitHub上的地址
4上为项目配置GHUnit,相对Xcode 5来说旧了但是安装过程还是类似的。
:编写测试的参考文档
还是以之前的那个项目为例,进荇GHUnit的配置并编写基于该框架的软件单元测试试。
1.新建一个Target选中空的工程模板:
2.选中目标工程为本工程:
然后打开我们可爱的终端,首先cd到Project-iOS目录下然后输入make命令,成功后的部分提示如下:
将主函数的return修改如下:
Command + R可以看到一个测试界面。点击右上角的Run就可以运行列表Φ的所有软件单元测试试:
点击表格中的一行,可以查看测试信息(当然控制台也有输出):
对比起使用XCTest框架在控制台的输出好看多了
建议使用GHUnit + OCMock组合进行软件单元测试试,功能强大界面美观当然也有人是用XCTest + xctool + OCMock的,xctool是Facebook出品应该也是非常强大的工具,但是小弟在机子上用brew一矗装不上xctool(暂时还没找到解决方法)所以这里就不说xctool的部分了。