iOS單元測試:Specta + Expecta + OCMock + OHHTTPStubs + KIF

來源:互聯網
上載者:User

標籤:...   repeat   obj   私人方法   assert   www   size   https   介面   

架構選擇參考這篇選型文章,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做一個基礎的瞭解還是有必要的。參考:1. https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/testing_with_xcode2. http://www.objc.io/issues/15-testing/xctest/,翻譯:http://objccn.io/issue-15-2/3. http://zixun.github.io/blog/2015/04/16/iosdan-yuan-ce-shi-xi-lie-dan-yuan-ce-shi-bian-ma-gui-fan/

BDD架構 — Specta1. 簡單介紹眼下主流的BDD架構,這些BDD架構在文法層面差點兒是同樣的,基本的差別在於他們的可配置能力和綁定的組件。

以下三個OC BDD架構相對於官方架構XCTest都具有更好的可讀性。另外如今已經有了比較流行的swift BDD架構: https://github.com/railsware/Sleipnir 和 https://github.com/Quick/Quick。

  • https://github.com/specta/specta
  • https://github.com/kiwi-bdd/Kiwi
  • https://github.com/pivotal/cedar

關於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/;
什麼是mock,refer: http://hackazach.net/code/2014/03/03/effective-testing-with-ocmock/: 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




以下有一個mock一個alert view show的過程


參考:
  • http://ocmock.org/reference/
  • http://ocmock.org/features/
  • http://ocmock.org/introduction/
  • http://www.archive.alexvollmer.com/posts/2010/06/28/making-fun-of-things-with-ocmock/
  • http://hackazach.net/code/2014/03/03/effective-testing-with-ocmock/。翻譯:http://zixun.github.io/blog/2015/04/16/iosdan-yuan-ce-shi-xi-lie-yi-ocmockchang-jian-shi-yong-fang-shi/
  • http://engineering.aweber.com/improving-ios-unit-tests-with-ocmock/

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
            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 原則優秀測試實踐原則,https://pragprog.com/magazines/2012-01/unit-tests-are-first:
  • Fast — 測試應該可以被常常執行
  • Isolated — 測試本身不能依賴於外部因素或其它測試的結果
  • Repeatable — 每次執行測試都應該產生同樣的結果
  • Self-verifying — 測試應該依賴於斷言,不須要人為幹預
  • Timely — 測試應該和生產代碼一同書寫
怎樣將測試結果收益最大化:不要將測試和實現細節耦合在一起。
  • 不要測試私人方法
  • 不要Stub私人方法
  • 不要Stub外部庫
  • 正確地Stub依賴
  • 不要測試建構函式

參考資料
  • http://www.objc.io/issues/15-testing/,(翻譯:http://objccn.io/issue-15/ )
  • https://github.com/artsy/eigen,很專業的APP的開源碼,http://objccn.io/issue-22-2/
  • <Functional Reactive Programming on iOS>: RAC + 單元測試
  • http://www.jianshu.com/p/73f9d719cee4
  • http://nshipster.com/unit-testing/
  • http://onevcat.com/2014/02/ios-test-with-kiwi/
  • http://onevcat.com/2014/05/kiwi-mock-stub-test/
  • https://github.com/dblock/fui,find unused objective-c imports
  • <Testing with Xcode>
  • <Pro iOS Continuous Integration>

iOS單元測試:Specta + Expecta + OCMock + OHHTTPStubs + KIF

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.