博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS单元測试:Specta + Expecta + OCMock + OHHTTPStubs + KIF
阅读量:6695 次
发布时间:2019-06-25

本文共 5038 字,大约阅读时间需要 16 分钟。

框架选择

參考这篇选型文章, ,尽管结论不一定全然适用,可是关于框架对照的地方还是值得阅读的。基于这篇文章,排除Kiwi框架之后,决定參考一些项目的源码,了解他们使用的測试方面的框架。

首先,參考 开源项目,其内部总体结构很完整,开发流程也很专业。至少比我知道的大多数国内团队都要专业:
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做一个基础的了解还是有必要的。
參考:
1. 
2.  ,翻译:
3. 

BDD框架  Specta

1. 简单介绍

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

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

关于specta与kiwi框架的对照,參考: ,这篇文章的结论是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语法简单介绍

能够參考   官网和 项目中的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,參考: ;sharedExamplesFor 设置多个spec之间共享的test case,第一个參数作为标识符。通过itShouldBehaveLike来执行spec中test case。第一个參数传入sharedExamplesFor设置时使用的标识符。注意。在describe局部使用sharedExamplesFor定义shared examples。能够在它作用域内覆盖全局的shared examples。
8) pending,仅仅打印一条log信息。不做測试。这个语句会给出一条警告,能够作为一開始集中书写行为描写叙述时还未实现的測试的提示。

断言框架  Expecta

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

mock框架  OCMock

了解OCMock 2.x中的具体features。能够參考:  ;了解OCMock 3.x的具体API。能够參考: ;
什么是mock,refer: 
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框架的使用方法也比較简单,因为我个人时间比較紧张,仅仅能抽出一两天的时间学习測试部分的知识,就不多说了,以下几篇文章都说的比較清楚,能够參考:  ,学习2.x和3.x的API的基本使用。

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

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

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

以下有一个mock一个alert view show的过程
參考:
  • 。翻译:

OHHTTPStubs

官方: 。这个框架是基于NSURLProtocol实现的。之前正好看过这部分的仅仅是,整理来说。这个框架的源码并不复杂,但实现还是比較巧妙的。具体的介绍和使用,在github上面介绍的很清楚,框架本身使用也比較简单:
[OHHTTPStubs 
stubRequestsPassingTest:^
BOOL(
NSURLRequest *request) {
 
return [request.URL.host 
isEqualToString:
@""];
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
           
statusCode:
200 
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依赖
  • 不要測试构造函数

參考资料

  • ,(翻译: )
  • ,很专业的APP的开源码,
  • <Functional Reactive Programming on iOS>: RAC + 单元測试
  • ,find unused objective-c imports
  • <Testing with Xcode>
  • <Pro iOS Continuous Integration>
你可能感兴趣的文章
Linux 统计文件夹,文件数量的命令
查看>>
spring hibernate实现动态替换表名(分表)
查看>>
精通ArrayList,关于ArrayList你想知道的一切
查看>>
KeyStore和TrustStore
查看>>
iOS - WKWebView加载不受信任的https (因用到IP地址加端口号去请求数据)
查看>>
vs和vim
查看>>
基于socket套接字发送大文件示例
查看>>
hdu1247 Hat’s Words
查看>>
Druid 介绍及配置
查看>>
Daily Scrum- 12/23
查看>>
Daily Scrum – 1/12
查看>>
pyinstaller---将py文件打包成exe
查看>>
【Prince2科普】Prince2的七大原则(7)
查看>>
Git指令操作
查看>>
学习小结(一) —— 基础数据结构
查看>>
WinDbg内核调试命令
查看>>
React文档(十七)非受控组件
查看>>
python中的metaclass
查看>>
大白叔叔专题之匹配、网络流(二)(第一题不是呐~)
查看>>
在centos中使用rpm安装包安装jenkins
查看>>