5.iOS測試總結


1. 什么是Mock

當我們在做單元測試的過程中,為了保持測試又短又快和測試的隔離性,希望盡可能少地去實例化一些具體的組件。在現在面向對象的系統中,被測試的對象很可能會依賴於幾個其他的對象,這時候我們就可以使用Mock去代替實例化這些對象。簡單來說,Mock就是在測試中偽造的具有預定行為的具體對象的替身對象。因為被測試對象無法分辨出具體對象和替身對象的差別,所以可以用替身對象去代替具體對象執行測試。

2. 使用Mock的好處

構造一些使用具體對象難以構造或難以出現的對象。如我們朝服務器(第三方服務器)發送請求,也許100次中只返回一次Error,而當我們要測試返回Error情況下的系統的行為是否符合預期,使用具體對象完成比較困難,這時候就需要構造MockObject。

減少一些耗時的操作,例如我們需要測試訪問數據庫,而訪問這個數據庫開銷巨大的時候,我們可以構造一個“虛擬”的數據庫,讓這個數據庫返回我們期望的特定值即可。

甚至有時候因為需要內網或者屏蔽等原因,無法連接服務器的情況,也可以使用“虛擬”一個網絡連接或服務器,讓它返回我們期望的數據即可。

3. 測試框架簡介

XCTest Or GHUnit

  XCTest GHUnit
簡述 蘋果官方提供的測試框架 相對熱門的第三方測試框架
優點 與XCode深度集成,無需安裝,而且可以享受蘋果后續的維護 有自己的GUI界面,測試結果直觀
缺點 測試結果難找且信息冗雜 集成度不如XCTest,安裝麻煩,不能單獨運行某個測試

XCTest和GHUnit都有各自的優缺點,相對來說GHUnit所提供的便利意義並不大,所以更多的開發者會選擇XCTest。

以下是一些Github上的一些知名的開源庫的測試框架選擇:

 

Expect Or OCHamcrest

  Expecta OCHamcrest
簡述 兩者都是斷言的擴展框架,都依賴於CocoaPods 起源於Java的Hamcrest,OCHamcrest是Hamcrest的一個Objective -C版本
優點 斷言不必考慮數據類型,可讀性強,使用方便 框架成熟,預定義的斷言更加豐富,可自定義斷言,可擴展性高
缺點 預定義斷言不夠多,可擴展性不高  

TDD Or BDD Or Not

TDD 的全稱是Test Driven Development,也就是測試驅動開發。它與軟件傳統的先開發后驗證的模式不同,是先驗證后開發。舉個例子來說,師傅砌磚,在TDD模式下會先拉線后砌磚,這樣砌出來的磚都是整齊的。而一些新來的師傅可能會先砌磚,然后再拉線檢查磚是否整齊,若磚不整齊,再繼續做后續的工作。這樣一聽,感覺TDD是不是很厲害,但實現起來非常困難。

BDD的全稱是Behavior Driven Development,也就是行為驅動開發,通過測試來推動整個開發的進行。BDD的理念是描述行為,所以感覺不是在寫代碼,而是在講故事。因此BDD的測試開發語言都十分接近自然語言,可讀性非常強,讓有眼前一亮。現有的BDD框架大多由三部分構成(Given....When....Then....)組成,下面是一段Objective-C語言的BDD框架Kiwi的一段測試代碼:

這個測試用例就是在說Give a Team, when newly created, it should have a name, and should have 11 players. 翻譯成中文就是一個足球隊成立的時候,它應該有一個隊名和11位球員。基本不用注釋就能很容易的讀懂這個測試做了什么。BDD框架的語法差別不大,十分易讀。目前iOS相關的BDD開源熱門框架有:

框架名稱 測試語言 GitHub Stars 備注
Kiwi Objective-C      3223 Kiwi自帶Mock功能,是基於OCMock實現的,所以不能和OCMock共用
Specta Objective-C      1692 Kiwi可以看做是帶有Mock和Expecta功能的Specta
Quick Swift(Objective-C)      4698  
Sleipnir Swift       795  
Cedar Objective-C      1079  

對於BDD框架的選擇,使用或不使用更多開發的項目。BDD測試代碼可讀性高,不過相對於XCTest和OCMock的組合,具有一定的學習成本且文檔不如后者豐富,在封裝過程中也失去了一定的靈活性。

目前使用過的BDD框架Kiwi和Specta都不支持單獨運行某個測試樣例,只能使用Command+U一次運行所有測試樣例,當測試樣例逐漸增多的時候就不得不運行一些不想要做的測試。

4. OCMock簡介

如果你已經理解了什么是Mock,那么OCMock就是Objective-C語言下的一個Mock框架。目前OCMock的版本是OCMock3,其API不太多,使用起來方便,這里簡單介紹一些:

Mock的模式:

模式 描述 API
Strict Mode       嚴格類型的Mock,當Mock對象調用了沒有被Stub的方法會拋出異
常。即嚴格意義上的完全Mock。
id strictMock = OCMStrictClassMock([NSUserDefaults class]);

 

Nice Mode      友好類型的Mock,當Mock對象調用了沒有被Stub的方法不會拋出
異常。目前是默認的Mock類型。

 id niceMock = OCMClassMock([NSUserDefaults class]);

 


Partial Mode

       部分類型的Mock,當Mock對象調用了沒有被Stub的方法會直接執
行具體對象的方法。

NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];

id partialMock = OCMPartialMock(defs);

 

Expect-Run-Verify 和  Verify after running

大多數的Mock框架都遵循了Expect-Run-Verify的原則,老版本的OCMock就是其中之一,這種方法出現了一些弊端。OCMock3支持了一種新的驗證方法Verify After Running,我們不用在運行結束就立即去驗證結果。只要在運行之后,只要在想要驗證的時候調用OCMVerify即可。

NSInvocation

在OCMock中如果使用了Block綁定參數,那么就需要和NSInvocation打交道,在Objective-C中,NSInvocation有兩個默認的參數(0: self , 1:_cmd),在綁定參數的時候要從2開始算。如:

- (void)downloadWeatherDataForZip:(NSString *)zip callback:(void (^)(NSDictionary *response))callback;

如果要動態綁定Callback,那么它對應的序號應該是3(0: self, 1: _cmd, 2: zip, 3: callback)。

通過[invoke getArgument:&storageVariableName atIndex:3];即可。

5. UI Tests相關

待補

6. Unit Tests相關

處理私有方法和屬性

按照測試的原理,我們不應該去測試私有的方法。但在我們測試的時候可能會調用一個私有方法或者私有屬性,如果不將其改為公有是無法去驗證這些行為的。這種情況,我們可以在測試文件的開頭用一個名為UnitTest的Category來暴露私有方法和屬性。如:

7. 相關頁面

英文原文:XCTest實戰經驗

中文翻譯:XCTest實戰經驗

iOS開發中的測試框架

單元測試框架選擇

OCMock官網

OCMock的常見使用方式

wwdc 2015 session UI Testing PDF

UITests Tutorial


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM