iOS开发中的测试框架 (转载)
作者:CrespoXiao授权
地址:http://www.jianshu.com/p/7e3f197504c1
我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以TDD还是算了吧,BDD就测测数据存取和重要环节,这很重要,一次性跑完测试单元检查接口或模块的可用性,这比打断点调试强多了吧,至于UI测试就算了吧(xcode7集成了),呵呵。
首先了解一下BDD与TDD的概念:
BDD(Behavior Driven Development),也就是行为驱动开发,它旨在解决具体问题,帮助开发人员确定应该测试些什么。
TDD(Test-Driven Development),就是测试驱动开发,通过测试来推动整个开发的进行。
github上搜TDD或BDD,语言选择objective-c,star最多的就是这2个:
https://github.com/kiwi-bdd/Kiwi/wiki
https://github.com/specta/specta
还有一个测试框架用的比较少,叫Cedar https://github.com/pivotal/cedar
此外,还找到2个Swift的测试框架,以后用Swift开发可以考虑使用:
https://github.com/railsware/Sleipnir
https://github.com/Quick/Quick
Cedar,Specta和Kiwi这3个框架就是目前Objc最流行的BDD测试框架了,其中Kiwi最受欢迎(根据github上的star数来推断,行为描述和期望写起来也比较易懂,至少我是这么认为的)。
不 过,Specta是 RAC 那帮人维护的,用于测试的黑魔法更多,我担心这帮人精力太分散顾及不上这个测试框架。但是有些使用测试框架经验丰富的人选择用回了XCTest,主要是因 为它跟Xcode集成的比较好,而且嫌BDD框架hold不住业务的发展,cmd+u可以一次性跑完所有的测试(试过3个框架目前都可以这样的)。
XCTest 与Xcode深度集成,而且可以享受Apple后续对XCTest升级的福利。XCTest 的优势和缺点都是由于它太简单了。你只需要创建一个类,使用 “test” 作为测试方法名的前缀,只需要这样就可以了,不需要再做其他的。不幸的是,这已经是 XCTest 的全部优点了。BDD 框架的附加功能的重要性是取决于项目的大小。我的结论是,XCTest 对中小型的工程来说是一个很好的选择,但是对于更大型的工程,就有必要参考一下像 Kiwi 或者 Specta 这样的 BDD 框架。Specta和Kiwi的区别就是Kiwi包含了Specta和OCmock以及Expeata所有的功能。换句话说Specta就是没有mock 和验证功能Kiwi。经测试,Kiwi与Specta是不能同时在项目中使用的,会Crash,不信你试试,不过各自可以与XCTest混合使用因为它们 是基于XCTest封装的。
Cedar,Kiwi, 以及 Specta 提供类似语法,我不能说其中一个框架要比其他所有都好,它们各有利弊,选择 BDD 框架归根结底来自个人偏好。我选择Kiwi是因为只需要在podfile导入一个Kiwi就行了,Specta则需要依赖别的第三方库,虽然灵活,但灵活 有灵活的坏处,当然也有好处,你喜欢就好,反正用得不爽别怨我。
如果使用Specta,还要引入OCmock/OCMockito以及Expeata/OCHamcrest一起配合使用。
OCMock Or OCMockito
这两个都是用来mock对象,Stub方法的,他们之间的区别在于使用OCMock的库比OCMockito的库多,而且文档和教程更加丰富。
Expecta Or OCHamcrest
这两个都是断言的扩展框架,Expecta不成熟,框架还有一些的问题。OCHamcrest更加成熟,而且可扩展性高,可以自定义自己的断言,更灵活。
BDD的理念是你不是在写代码,而是在讲故事。而整个故事是由Given…When…Then组成。我们可以来看看BDD框架Kiwi的一段测试代码:
describe(@
"Team"
, ^{
context(@
"when newly created"
, ^{
it(@
"has a name"
, ^{
id team = [Team team]; [[team.name should] equal:@
"Black Hawks"
];
});
it(@
"has 11 players"
, ^{
id team = [Team team]; [[[team should] have:11] players];
});
});
});
这个测试用例就是在说Given a Team,When newly created,it should have a name, and should have 11 players,基本上不需要注释就能知道在干嘛。
参考:http://onevcat.com/2014/05/kiwi-mock-stub-test/
不同类型的模拟对象的基本定义:
double 可以理解为置换,它是所有模拟测试对象的统称,我们也可以称它为替身。一般来说,当你创建任意一种测试置换对象时,它将被用来替代某个指定类的对象。
stub 可以理解为测试桩,它能实现当特定的方法被调用时,返回一个指定的模拟值。如果你的测试用例需要一个伴生对象来提供一些数据,可以使用 stub 来取代数据源,在测试设置时可以指定返回每次一致的模拟数据。
spy 可以理解为侦查,它负责汇报情况,持续追踪什么方法被调用了,以及调用过程中传递了哪些参数。你能用它来实现测试断言,比如一个特定的方法是否被调用或者是否使用正确的参数调用。当你需要测试两个对象间的某些协议或者关系时会非常有用。
mock 与 spy 类似,但在使用上有些许不同。spy 追踪所有的方法调用,并在事后让你写断言,而 mock 通常需要你事先设定期望。你告诉它你期望发生什么,然后执行测试代码并验证最后的结果与事先定义的期望是否一致。
fake 是一个具备完整功能实现和行为的对象,行为上来说它和这个类型的真实对象上一样,但不同于它所模拟的类,它使测试变得更加容易。一个典型的例子是使用内存中的数据库来生成一个数据持久化对象,而不是去访问一个真正的生产环境的数据库。
实践中,这些术语常常用起来不同于它们的定义,甚至可以互换。它们自认为自己是 "mock 对象框架",但是其实它们也提供 stub 的功能,不要太过于陷入这些词汇的细节。
下面讲讲Kiwi的使用,尽量简单,以便快速上手,当然详情还是得看官方文档,链接奉上:
https://github.com/kiwi-bdd/Kiwi/wiki
http://onevcat.com/2014/02/ios-test-with-kiwi/
1.Kiwi的安装
podfile中写入
target
'OneTravelTests'
, :exclusive =>
true
do
pod
'Kiwi'
end
然后pod install或pod update就可以了。
可以安装一个xcode插件http://alcatraz.io,里面有Kiwi的template,安装一下,然后就可以使用Kiwi了。然而有人说插件用不了,怪我咯?懒得解释了,看这里吧:
https://github.com/cikelengfeng/RPAXU
2.Kiwi的基本语法解释
上3张图,一切尽在不言中。
kiwi基本语法解释
mock与stub解释
测试数据请求
3.我们应该/不应该测试什么
BDD 的第一个单词就表明了这一点,你不应该关注于测试,而是应该关注行为。这个看似毫无意义的变化提供了应该测试什么的准确答案:你应该测试行为。
例如你设计的一个对象,它有一个接口定义了其方法和依赖关系。这些方法和依赖,声明了你对象的约定,它们定义了如何与应用的其他部分交互,以及它的功能是什么。它们定义了对象的行为。同时这也应该是你的目标:测试你对象的行为方式。
不应该测试什么呢?
不要测试私有方法:私有方法意味着私有,如果你感到有必要测试一个私有方法,那么那个私有方法一定含有概念性错误,通常是作为私有方法,它做的太多了, 从而违背了单一职责原则。
不要 Stub 私有方法:Stub 私有方法和测试私有方法具有相同的危害,更重要的是,Stub 私有方法将会使程序难以调试。通常来说,用于Stub的库会依赖于一些不寻常的技巧来完成工作,这使得发现一个测试为什么会失败变的困难。
不要测试构造函数:构造函数定义的是实现细节,你不应该测试构造函数,这是因为我们认同测试应该与实现细节解耦这一观点。
不要 Stub 外部库:第三方代码不应该在你的测试中直接出现。
4.测试的目的
使重构更简单 —— 你可以自信的修改实现细节,而不用去触及公有 API。
避免代码恶化—— 恶化在什么时候发生?在你修改代码的时候。
提供了可执行的说明和文档 —— 你在什么时候更想知道软件实际上是如何工作的?在你想修改它们的时候。
减少了创建软件的时间 —— 怎么减少时间的?是通过更快速地修改你的代码,出错时测试会自信地告诉你哪里出错了。
降低了创建软件的代价 —— 时间就是金钱,朋友。
测试应该:
很快速(Fast) —— 测试应该能够被经常执行。
能隔离(Isolated) —— 测试本身不能依赖于外部因素或者其他测试的结果。
可重复(Repeatable) —— 每次运行测试都应该产生相同的结果。
带自检(Self-verifying) —— 测试应该包括断言,不需要人为干预。
够及时(Timely) —— 测试应该和生产代码一同书写。
5.UI测试
关于UI测试,需要测试的是用户的交互,而不是应用的外观,Xcode7中新增了UI Testing,具体可以看wwdc 2015 session :406_hd_ui_testing_in_xcode。
好了,没了,我有严重的拖延症,哎。
更多请参考:http://www.objc.io
iOS开发中的测试框架 (转载)的更多相关文章
- iOS开发中的测试框架
转载作者:@crespoxiao 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以TDD还是算了吧,BDD就测测数据存取和重要环节,这很重要,一次性跑完测试单元检查接口 ...
- 简述 Ruby 与 DSL 在 iOS 开发中的运用
阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain Specific Language) 翻译成中文就是:"领域特定语言".首先,从定义就 ...
- 白话 Ruby 与 DSL 以及在 iOS 开发中的运用
每日一篇优秀博文 2017年10月7日 周六 白话 Ruby 与 DSL 以及在 iOS 开发中的运用 阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain S ...
- iOS开发中遇到的一些问题及解决方案【转载】
iOS开发中遇到的一些问题及解决方案[转载] 2015-12-29 [385][scrollView不接受点击事件,是因为事件传递失败] // // MyScrollView.m // Creat ...
- [转载]对iOS开发中内存管理的一点总结与理解
对iOS开发中内存管理的一点总结与理解 做iOS开发也已经有两年的时间,觉得有必要沉下心去整理一些东西了,特别是一些基础的东西,虽然现在有ARC这种东西,但是我一直也没有去用过,个人觉得对内存操作 ...
- iOS开发中的单元测试(三)——URLManager中的测试用例解析
本文转载至 http://www.cocoachina.com/cms/plus/view.php?aid=8088 此前,我们在<iOS开发中的单元测试(一)&(二)>中介绍 ...
- iOS开发中静态库之".framework静态库"的制作及使用篇
iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...
- iOS开发中打电话发短信等功能的实现
在APP开发中,可能会涉及到打电话.发短信.发邮件等功能.比如说,通常一个产品的"关于"页面,会有开发者的联系方式,理想情况下,当用户点击该电话号码时,能够自动的帮用户拨出去,就涉 ...
- iOS开发之常用第三方框架(下载地址,使用方法,总结)
iOS开发之常用第三方框架(下载地址,使用方法,总结) 说句实话,自学了这么久iOS,如果说我不知道的但是又基本上都摸遍了iOS相关知识,但是每次做项目的时候,遇到难一点的地方或者没试过的东西就闷了. ...
随机推荐
- matlab 中保存某几个变量
save AOA.mat dingjiao RMSE%保存变量dingjiao,RMSE于AOA.mat clear all;%当删除所有数据之后 load AOA.mat%还可以读出这两个变量的数 ...
- Ubuntu忘记管理员密码
Ubuntu中不小心把管理员密码忘记了,真叫人头大. 现提供一个解决方案: 1.重启 Ubuntu 系统,按 Esc 进入GRUB 菜单界面,如下图: 2.选择recovery mode. (第二个) ...
- UNIX 网络编程第五章读书笔记
刚看完 UNIX 第五章内容,我想按照自己的方式将自己获得的知识梳理一遍,以便日后查看!先贴上一段简单的 TCP 服务器端代码: #include <sys/socket.h> #incl ...
- zoj 3351 Bloodsucker(概率 dp)
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4530 dp[i]表示现在存在i个吸血鬼要达成目标(全为吸血鬼)天数的数学 ...
- struts2的action中获得request response session 对象
在struts2中有两种方式可以得到这些对象 1.非IoC方式 要获得上述对象,关键Struts 2中com.opensymphony.xwork2.ActionContext类.我们可以通过它的静态 ...
- 结构体buf_block_t
/** Buffer block for which an uncompressed page exists */ typedef struct buf_block_struct buf_block_ ...
- TRSWCM学习问题总结
1,置标属性"id"是用来制定调用那个栏目的数据(全字配备,可以文字匹配好奇怪,好不专业.所以建议创建栏目或者站点的时候,将唯一标识设置成英文,这样才符合程序比对习惯) 2,需要添 ...
- SPOJ 962 Intergalactic Map (从A到B再到C的路线)
[题意]在一个无向图中,一个人要从A点赶往B点,之后再赶往C点,且要求中途不能多次经过同一个点.问是否存在这样的路线.(3 <= N <= 30011, 1 <= M <= 5 ...
- MVC 5 的 EF6 Code First 入门
英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with Entity Framework 6 Code First using MVC 5 系列 ...
- SoapUI入门
注:需要使用发布的webService接口 我们一般用的是impl接口调用,不大用得上soapUI.看到一份简历上写了使用soapUI做webService测试,想了解一下什么是soapUI soap ...