標籤:... 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