框架选择

參考这篇选型文章,http://zixun.github.io/blog/2015/04/11/iosdan-yuan-ce-shi-xi-lie-dan-yuan-ce-shi-kuang-jia-xuan-xing/,尽管结论不一定全然适用,可是关于框架对照的地方还是值得阅读的。基于这篇文章,排除Kiwi框架之后,决定參考一些项目的源码,了解他们使用的測试方面的框架。


首先,參考https://github.com/artsy/eigen开源项目,其内部总体结构很完整,开发流程也很专业。至少比我知道的大多数国内团队都要专业:
eigen: Specta + OCMock + Expecta + OHHTTPStubs + FBSnapshotTestCase + "Expecta+Snapshots" + "XCTest+OHHTTPStubSuiteCleanUp”。

其次,參考公司内部别的项目使用情况。发现使用下面框架来做測试方面的事情: Specta + Expecta + OCMock + OHTTPStubs + KIF(UI Test)

so,我决定选择 Specta (BDD框架) + Expecta(断言框架) + OCMock(mock框架) + OHHTTPStubs(http stub框架) + KIF(UI Test) 做測试框架来学习。


XCTest简单介绍

因为我决定不直接使用XCTest作为測试框架。可是又因为Specta是基于XCTest进行封装的,所以对XCTest做一个基础的了解还是有必要的。
參考:


BDD框架 — Specta

1. 简单介绍

眼下主流的BDD框架,这些BDD框架在语法层面差点儿是同样的,基本的差别在于他们的可配置能力和绑定的组件。

以下三个OC BDD框架相对于官方框架XCTest都具有更好的可读性。另外如今已经有了比較流行的swift BDD框架:https://github.com/railsware/Sleipnir 和 https://github.com/Quick/Quick


关于specta与kiwi框架的对照,參考:http://appleprogramming.com/blog/2014/01/18/tdd-with-specta-and-expecta/,这篇文章的结论是specta相对于kiwi有更加优雅的语法,对于我这样的刚開始使用的新手,果断採用specta这样的各种完胜的框架。Specta框架具有一下特点:
  • An OC RSpec-like BDD DSL
  • Quick and easy set up
  • Build on top of XCTest
  • Excellent Xcode integration

2. Specta BDD DSL语法简单介绍

能够參考 https://github.com/specta/specta 官网和https://github.com/artsy/eigen项目中的test
case代码来学习语法
1) SpecBegin 声明了一个測试类。SpecEnd 结束了类声明
2) describe (context) 块声明了一组实例
3) it (example/specify) 是一个单一的样例
4) beforeAll 是一个执行于全部同级块之前的块,仅仅执行一次。afterAll 与beforeAll相反,是在全部同级块之后执行的块。仅仅执行一次。
5) beforeEach/afterEach,在每一个同级块执行的时候,都会执行一次,而beforeAll/afterAll仅仅会执行一次
6) it/waitUntil/done()。异步调用,注意完毕异步操作之后。必须调用done()函数。例如以下:
  • it(@"should do some stuff asynchronously", ^{

        waitUntil(^(DoneCallback done) {

          // Async example blocks need to invoke done() callback.

          done();

        });

      });

7) sharedExamplesFor 和 itShouldBehaveLike结合在一起。能够实如今不同的spec之间共享同一套test case,參考:http://artandlogic.com/2014/02/specta-shared-behavior/;sharedExamplesFor
设置多个spec之间共享的test case,第一个參数作为标识符。通过itShouldBehaveLike来执行spec中test case。第一个參数传入sharedExamplesFor设置时使用的标识符。注意。在describe局部使用sharedExamplesFor定义shared examples。能够在它作用域内覆盖全局的shared examples。

8) pending,仅仅打印一条log信息。不做測试。这个语句会给出一条警告,能够作为一開始集中书写行为描写叙述时还未实现的測试的提示。


断言框架 — Expecta


使用方法能够參考开源项目: https://github.com/artsy/eigen。从中找到相应的代码学习是最好的方式。假设须要找到很多其它更全面的使用方法,能够去项目官方站点:https://github.com/specta/expecta。截取一段eigen上面代码,基本上就能够了解Expecta框架的基本使用方法了,例如以下图中
expect(mapView.nextZoomScale).to.equal(mapView.annotationZoomScaleThreshold)





mock框架 —
OCMock


了解OCMock 2.x中的具体features。能够參考: http://ocmock.org/features/;了解OCMock 3.x的具体API。能够參考:http://ocmock.org/reference/


In a modern Object Oriented system, the component under test will likely have several object dependencies. Instead of instantiating dependencies as concrete classes, we use mocks. Mocks are ‘fake’ objects with pre-defined behavior to stand-in for concrete objects during testing. The component under test does not know the difference! With mocks, a component can be tested with confidence that it behaves as designed within a larger system. 

OCMock框架的使用方法也比較简单,因为我个人时间比較紧张,仅仅能抽出一两天的时间学习測试部分的知识,就不多说了,以下几篇文章都说的比較清楚,能够參考:http://zixun.github.io/blog/2015/04/16/iosdan-yuan-ce-shi-xi-lie-yi-ocmockchang-jian-shi-yong-fang-shi/ ,学习2.x和3.x的API的基本使用。

另外能够參考开源项目 https://github.com/artsy/eigen,学习当中的OCMock
API的使用,框架使用比較简单,看看就懂了,不须要多说。


eigen的一个test case,注意在运行完成的时候,须要调用stopMocking。OCMockObject是基于runtime方法转发实现的。mock一个对象,就是对这个对象的方法进行转发的过程,运行完成须要调用stopMocking,否则会影响其它test case的运行。

以下能够看出一个OCMock基本过程:获得OCMockObject -> stub方法 -> 设置expect ->
verify校验运行结果 -> 调用stopMocking


watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">


以下有一个mock一个alert view show的过程



參考:

OHHTTPStubs

官方:https://github.com/AliSoftware/OHHTTPStubs。这个框架是基于NSURLProtocol实现的。之前正好看过这部分的仅仅是,整理来说。这个框架的源码并不复杂,但实现还是比較巧妙的。具体的介绍和使用,在github上面介绍的很清楚,框架本身使用也比較简单:
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {

  return [request.URL.host isEqualToString:@"mywebservice.com"];

} withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {

  // Stub it with our "wsresponse.json" stub file (which is in same bundle as self)

  NSString* fixture = OHPathForFile(@"wsresponse.json", self.class);

  return [OHHTTPStubsResponse responseWithFileAtPath:fixture

             headers:@{@"Content-Type":@"application/json"}];

}];
这个框架的主要用法就是上面这个演示样例,用法非常明显易用。结合unit test使用的时候。须要使用网络请求的时候。能够在it或者beforeAll或者beforeEach的时候进行stub request。即上面这段代码的行为。可是不要忘记的是。须要在tear down的时候,即specta的afterAll的时候,记得调用 [OHHTTPStubs removeAllStubs] 。
注意,这里仅仅是使用NSURLProtocol来stub request。不会影响被測试的请求接口的測试。请求是异步的话,能够使用Specta的it/waitUntil/done()流程对请求进行測试,假设使用XCTest的话,OHTTPStubs给出了一个wiki解决。使用XCTestExpectation来搞定。我认为挺有意思:
- (void)testFoo

{

  NSURLRequest* request = ...

  XCTestExpectation* responseArrived = [self expectationWithDescription:@"response of async request has arrived"];

  __block NSData* receivedData = nil;

  [NSURLConnection sendAsynchronousRequest:request

                                     queue:[NSOperationQueue mainQueue]

                         completionHandler:^(NSURLResponse* response, NSData* data, NSError* error)

   {

     receivedData = data;

     [responseArrived fulfill];

   }

  ];



  [self waitForExpectationsWithTimeout:timeout handler:^{

    // By the time we reach this code, the while loop has exited

    // so the response has arrived or the test has timed out

    XCTAssertNotNil(receivedData, @"Received data should not be nil");

  }];

}

因为NSURLProtocol的局限性。OHHTTPStubs没法用来測试background sessions和模拟数据上传。


F.I.R.S.T 原则

  • Fast — 測试应该可以被常常执行
  • Isolated — 測试本身不能依赖于外部因素或其它測试的结果
  • Repeatable — 每次执行測试都应该产生同样的结果
  • Self-verifying — 測试应该依赖于断言,不须要人为干预
  • Timely — 測试应该和生产代码一同书写
怎样将測试结果收益最大化:不要将測试和实现细节耦合在一起。
  • 不要測试私有方法
  • 不要Stub私有方法
  • 不要Stub外部库
  • 正确地Stub依赖
  • 不要測试构造函数

參考资料

iOS单元測试:Specta + Expecta + OCMock + OHHTTPStubs + KIF的更多相关文章

  1. iOS 单元測试之XCTest具体解释(一)

    原创blog,转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的iOS-SDK具体解释专栏 http://blog.csdn.net/column/details/huang ...

  2. ios单元測试之GHUnit

    1.相同创建一个測试的project, 2.通过cocoaPod来下载GHUnit框架,或者到github上下载.由于这个框架是开源的第三方框架. 同一时候加入QuartCore.framework( ...

  3. [iOS翻译]《iOS7 by Tutorials》在Xcode 5里使用单元測试(上)

    简单介绍: 单元測试是软件开发的一个重要方面.毕竟,单元測试能够帮你找到bug和崩溃原因,而程序崩溃是Apple在审查时拒绝app上架的首要原因. 单元測试不是万能的,但Apple把它作为开发工具包的 ...

  4. 利用Continuous Testing实现Eclipse环境自己主动单元測试

    当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...

  5. 在Eclipse中使用JUnit4进行单元測试(0基础篇)

    本文绝大部分内容引自这篇文章: http://www.devx.com/Java/Article/31983/0/page/1 我们在编写大型程序的时候,须要写成千上万个方法或函数,这些函数的功能可能 ...

  6. C语言单元測试

    C语言单元測试 对于敏捷开发来说,单元測试不可缺少,对于Java开发来说,JUnit非常好,对于C++开发,也有CPPUnit可供使用,而对于传统的C语言开发,就没有非常好的工具可供使用,能够找到的有 ...

  7. OpenStack中给wsgi程序写单元測试的方法

    在 OpenStack 中, 针对web应用, 有三种方法来写单元測试 1) 使用webob生成模拟的request from __future__ import print_function imp ...

  8. Android单元測试之JUnit

    随着近期几年測试方面的工作慢慢火热起来.常常看见有招聘測试project师的招聘信息.在Java中有单元測试这么一个JUnit 方式,Android眼下主要编写的语言是Java,所以在Android开 ...

  9. 让你提前认识软件开发(19):C语言中的协议及单元測试演示样例

    第1部分 又一次认识C语言 C语言中的协议及单元測试演示样例 [文章摘要] 在实际的软件开发项目中.常常要实现多个模块之间的通信.这就须要大家约定好相互之间的通信协议,各自依照协议来收发和解析消息. ...

随机推荐

  1. hdu 4531 bfs(略难)

    题目链接:点我 第一次不太清楚怎么判重,现在懂了,等下次再做 /* *HDU 4531 *BFS *注意判重 */ #include <stdio.h> #include <stri ...

  2. 【洛谷】4310: 绝世好题【二进制DP】

    P4310 绝世好题 题目描述 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). 输入输出格式 输入格式: 输入文件共2行 ...

  3. the elements of computing systems 的读书笔记2

    懒癌发作,本来计划是两到三天就一个unit的,没想到一直拖到今天才完成第二部分(6-8章). 第6章,介绍了hack汇编到二进制,也就是用翻译到01来表示.从课后习题来看,这一章目的就是设计一个程序( ...

  4. X-010 FriendlyARM tiny4412 uboot移植之移植网卡驱动TFTP用起来

    <<<<<<<<<<<<<<<<<<<<<<<<< ...

  5. 模拟拖拽图片 碰撞检测 DOM 鼠标事件 闭包

    <!doctype html><html lang="en"> <head> <meta charset="UTF-8" ...

  6. chrome 浏览器 console 加入 jquery 测试调试 一介布衣

    chrome 浏览器 console 加入 jquery 测试调试 一介布衣   var jquery = document.createElement('script'); jquery.src = ...

  7. [Android] 字体使用dp单位避免设置系统字体大小对排版的影响

    [Android] 字体使用dp单位避免设置系统字体大小对排版的影响 以魄族mx3为例,在设置->显示->字体大小中能够选择字号大小例如以下图: 图1. 魄族mx3 会导致软件在有固定定高 ...

  8. Node.js是一个事件驱动I/O服务端JavaScript环境

    Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎.目的是为了提供撰写可扩充网络程序,如Web服务.第一个版本由Ryan Dahl于2009年发布,后来,Jo ...

  9. SyncTrayzor -- Windows tray utility / filesystem watcher / launcher for syncthing

    SyncTrayzor is a little tray utility for Syncthing on Windows. It hosts and wraps Syncthing, making ...

  10. How to check Ubuntu version

    Below you can find some tips on how to check Ubuntu version you are currently running. The first pla ...