转载作者:@crespoxiao

我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以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:] 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开发中的测试框架的更多相关文章

  1. iOS开发中的测试框架 (转载)

      作者:CrespoXiao授权 地址:http://www.jianshu.com/p/7e3f197504c1 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以T ...

  2. 简述 Ruby 与 DSL 在 iOS 开发中的运用

    阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain Specific Language) 翻译成中文就是:"领域特定语言".首先,从定义就 ...

  3. 白话 Ruby 与 DSL 以及在 iOS 开发中的运用

    每日一篇优秀博文 2017年10月7日 周六 白话 Ruby 与 DSL 以及在 iOS 开发中的运用 阅读本文不需要预先掌握 Ruby 与 DSL 相关的知识 何为 DSL DSL(Domain S ...

  4. iOS开发中静态库之".framework静态库"的制作及使用篇

    iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...

  5. iOS开发中打电话发短信等功能的实现

    在APP开发中,可能会涉及到打电话.发短信.发邮件等功能.比如说,通常一个产品的"关于"页面,会有开发者的联系方式,理想情况下,当用户点击该电话号码时,能够自动的帮用户拨出去,就涉 ...

  6. iOS开发之常用第三方框架(下载地址,使用方法,总结)

    iOS开发之常用第三方框架(下载地址,使用方法,总结) 说句实话,自学了这么久iOS,如果说我不知道的但是又基本上都摸遍了iOS相关知识,但是每次做项目的时候,遇到难一点的地方或者没试过的东西就闷了. ...

  7. iOS开发-常用第三方开源框架介绍

    iOS开发-常用第三方开源框架介绍 图像: 1.图片浏览控件MWPhotoBrowser        实现了一个照片浏览器类似 iOS 自带的相册应用,可显示来自手机的图片或者是网络图片,可自动从网 ...

  8. iOS开发中的单元测试(三)——URLManager中的测试用例解析

    本文转载至 http://www.cocoachina.com/cms/plus/view.php?aid=8088   此前,我们在<iOS开发中的单元测试(一)&(二)>中介绍 ...

  9. iOS开发中静态库制作 之.a静态库制作及使用篇

    iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...

随机推荐

  1. JavaScript——new Date().getMonth()

    new Date().getMonth(); 说明:参照现在的月份,getMonth()返回的是0-11的数字,也就是说0=1月,1=2月……11=12月 当前的月份就是,new Date().get ...

  2. rmmod 无法卸载模块问题

    用insmod加载驱动模块成功后,用rmmod无法卸载 解决方法:在板子上建立一个空目录:lib/modules/2.6.30.4/

  3. PHP设计模式之装饰者模式

    <?php /* 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. */ header("Content-type:text/html; cha ...

  4. (六)6.10 Neurons Networks implements of softmax regression

    softmax可以看做只有输入和输出的Neurons Networks,如下图: 其参数数量为k*(n+1) ,但在本实现中没有加入截距项,所以参数为k*n的矩阵. 对损失函数J(θ)的形式有: 算法 ...

  5. 一起学CUDA(一)

    前提是电脑的显卡支持CUDA,N卡一般是支持的,如果是A卡就没办法了.主要针对Windows环境,Linux和Mac也有相应的安装包.CUDA环境搭建:Step1:安装代码环境VS2010:Step2 ...

  6. ORACLE 修改日志大小及增加日志成员

    日志文件能不能resize,直接扩大日志文件的大小?10g是不能的. 网上的一般方法就是新建两个临时日志组(oracle至少要求两个日志组),切换到这两个临时日志组后,删掉重建扩大或缩小,再添加日志组 ...

  7. 如何使用java中的对象

    使用java中的对象,分2步: 1.创建一个对象: 2.使用对象的属性和方法. 见下面的示例代码: package com.imooc; //1.定义一个类 public class Telphone ...

  8. 关于Xcode的项目文件夹

    当我们在打开的项目中,对某个文件夹 Show in Finder的时候,发现对代码的分类文件夹没有全在一堆,在项目中明明对代码分了类,为什么在Finder中没有文件夹?? 这是因为,Xcode项目中的 ...

  9. mysql的password()函数和md5函数

    password用于修改mysql的用户密码,如果是应用与web程序建议使用md5()函数, password函数旧版16位,新版41位,可用select length(password('12345 ...

  10. App中嵌入网页浏览器

    TOWebViewController 插件 NSURL *url =[NSURL URLWithString:@"http://192.168.1.134:8180/Home/IndexP ...