iOS單元測試

1、什么是單元測試

單元測試又稱為模塊測試仆救,是指對軟件中的最小可測試單元進行檢查和驗證抒和。是開發(fā)者編寫的一小段代碼,用于檢驗被測代碼的一個很小的彤蔽、很明確的功能是否正確摧莽。

1、單元測試的本質

  1. 是一種驗證行為

    單元測試在開發(fā)前期檢驗了代碼邏輯的正確性顿痪,開發(fā)后期范嘱,無論是修改代碼內部抑或重構,測試的結果為這一切提供了可量化的保障员魏。

  2. 是一種設計行為

    為了可進行單元測試丑蛤,尤其是先寫單元測試(TDD),我們將從調用者思考撕阎,從接口上思考受裹,我們必須把程序單元設計成接口功能劃分清晰的,易于測試的虏束,且與外部模塊耦合性盡可能小棉饶。

  3. 是一種快速回歸的方式

    在原代碼基礎上開發(fā)及修改功能時,單元測試是一種快捷镇匀,可靠的回歸照藻。

  4. 是程序優(yōu)良的文檔

    從效果上而言,單元測試就像是能執(zhí)行的文檔汗侵,說明了在你用各種條件調用代碼時幸缕,你所能期望這段代碼完成的功能群发。

2、在什么時候我們需要單元測試

  1. 當發(fā)現自己改了代碼之后发乔,經常需要手動驗證的時候
  2. 改了代碼之后, 怕影響其他地方的bug
  3. 多人合作項目熟妓,可能交給其他人不放心別人改你的代碼的時候

以上都可以通過寫測試案例,進行自動化測試栏尚,從而減少bug起愈。

3、單元測試的目的

  1. 保證代碼的質量

    代碼可以通過編譯器檢查語法的正確性译仗,卻不能保證代碼邏輯是正確的抬虽,尤其包含了許多單元分支的情況下,單元測試可以保證代碼的行為和結果與我們的預期和需求一致纵菌。在測試某段代碼的行為是否和你的期望一致時阐污,你需要確認,在任何情況下产艾,這段代碼是否都和你的期望一致,譬如參數可能為空滑绒,可能的異步操作等闷堡。

  2. 保證代碼的可維護性

    保證原有單元測試正確的情況下,無論如何修改單元內部代碼疑故,測試的結果應該是正確的杠览,且修改后不會影響到其他的模塊。

  3. 保證代碼的可擴展性

    為了保證可行的可持續(xù)的單元測試纵势,程序單元應該是低耦合的踱阿,否則,單元測試將難以進行钦铁。

2软舌、單元測試的兩種設計思想

1、 測試驅動開發(fā) Test Driven Development(TDD)

先寫測試程序牛曹,然后編碼實現其功能佛点。

測試驅動開發(fā)是戴兩頂帽子思考的開發(fā)方式:先戴上實現功能的帽子,在測試的輔助下黎比,快速實現其功能超营;再戴上重構的帽子,在測試的保護下阅虫,通過去除冗余的代碼演闭,提高代碼質量。

2颓帝、 行為驅動開發(fā) Behavior Driven Development(BDD)

它通過用自然語言書寫非程序員可讀的測試用例擴展了 測試驅動開發(fā)方法(TDD)米碰。這讓開發(fā)者得以把精力集中在代碼應該怎么寫窝革,而不是技術細節(jié)上,而且也最大程度的減少了將代碼編寫者的技術語言與商業(yè)客戶见间、用戶聊闯、利益相關者、項目管理者等的領域語言之間來回翻譯的代價米诉。

例如現在比較流行的框架kiwi就是行為驅動開發(fā)菱蔬。下文會簡單展示kiwi的使用和設計思想。

3史侣、使用Xcode編寫第一個測試案例拴泌。

demo下載

1、 創(chuàng)建單元測試Target

image

如上圖所視,在創(chuàng)建項目的時候就可以選擇是否添加單元測試惊橱。如果創(chuàng)建項目的時候沒有添加蚪腐,也可以通過
file - new - target - Test - Unit Testing bundle 來創(chuàng)建

2、 單元測試類介紹

image

如上圖所示税朴,其實Xcode已經說的很清楚了回季。

  • setUp 用于做一些初始化代碼
  • TearDown 用于對象的銷毀
  • 所有測試類都必須繼承XCTestCase
  • 測試方法必須以testXXX開頭,Xcode會自動識別出所有的測試方法
  • 在一個類中測試方法的調用順序是按照方法的順序來調用的

調用

  • 執(zhí)行所有測試方法:command + u
  • 只執(zhí)行某個測試方法:點擊方法前的菱形(目前是對號/錯號)
  • 執(zhí)行某個類的所有測試方法:點擊類前的菱形(目前是對號/錯號)

3正林、寫案例測試

我們在viewController里面添加一個方法計算工資稅泡一。如圖所示


image

我們想驗證這個方法是否計算正確,便可以創(chuàng)建測試來測試觅廓。如下圖所示

image

點每一個方法的左邊的菱形圖標就會單獨測試鼻忠。如果點類名旁邊的菱形圖標便會全類測試,執(zhí)行方法按順序執(zhí)行杈绸。

如上圖所示帖蔓,第二第三個方法驗證通過,第一個并沒有通過瞳脓。是我們通過XCTAssert為我們提供的系統(tǒng)斷言 XSTAsserTrue 進行的判斷塑娇,那么除了 XSTAsserTrue
還有那些可以用于判斷的呢。下面簡單介紹常用的

4劫侧、常用斷言

- (void)testExample {
    NSLog(@"--- 失敗之前的輸出");
    XCTFail(@"無論怎么樣都是報錯");
    NSLog(@"--- 失敗之后的輸出");
}

- (void)testNil {
//    XCTAssertNil(expression, ...)
//    expression為空時通過钝吮,否則測試失敗。
//    expression接受id類型的參數板辽。
    
//    XCTAssertNotNil(expression, ...)
//    expression不為空時通過奇瘦,否則測試失敗。
    
    NSString *name = @"小明";
//    XCTAssertNil(name, @"報錯信息輸出");
//    XCTAssertNotNil(name, @"viewcontroller 是 nil ");
}

- (void)testTrue {
//    XCTAssert(expression, ...)
//    expression為true時通過劲弦,否則測試失敗耳标。
//    expression接受boolean類型的參數。

//    XCTAssertTrue(expression, ...)
//    expression為true時通過邑跪,否則測試失敗次坡。
//    expression接受boolean類型的參數呼猪。
    
//    XCTAssertFalse(expression, ...)
//    expression為false時通過,否則測試失敗砸琅。
//    expression接受boolean類型的參數宋距。
    
    NSInteger number = 10;
//    XCTAssert(number == 10, @"報錯信息輸出");
//    XCTAssertTrue(number == 10, @"報錯信息輸出");
    XCTAssertFalse(number != 10, @"報錯信息輸出");
}

- (void)testEqual {
//    XCTAssertEqualObjects(expression1, expression2, ...)
//    expression1和expression1地址相同時通過,否則測試失敗症脂。
//    expression接受id類型的參數谚赎。
//
//    XCTAssertNotEqualObjects(expression1, expression2, ...)
//    expression1和expression1地址不相同時通過,否則測試失敗诱篷。
//    expression接受id類型的參數壶唤。
//
//    XCTAssertEqual(expression1, expression2, ...)
//    expression1和expression1相等時通過,否則測試失敗棕所。
//    expression接受基本類型的參數(數值闸盔、結構體之類的)。
//
//    XCTAssertNotEqual(expression1, expression2, ...)
//    expression1和expression1不相等時通過琳省,否則測試失敗迎吵。
//    expression接受基本類型的參數。
 
//    NSString *name = @"小明";
//    NSString *name2 = name;
//    NSString *name3 = @"小紅";
//
//    XCTAssertEqualObjects(name, name2, @"name1 不等于 name 2");
//    XCTAssertEqualObjects(name, @"小明", @"name1 不等于 小明");
//    XCTAssertEqualObjects(name, name3, @"name1 不等于 name3");
    
    NSInteger number1 = 10;
    NSInteger number2 = 12;
    
//    XCTAssertEqual(number1, number2, @"number1 不等于 number 2");
    XCTAssertNotEqual(number1, number2, @"number1 等于 number 2");
}

點擊可查閱更多斷言

5针贬、異步測試

XCTestExpectation 是系統(tǒng)為我們提供的異步測試的API击费,可以幫助我們測試接口,響應速度等坚踩。

image

如圖 我們創(chuàng)建分線程來計算工資稅

測試方法,如下圖

  1. 創(chuàng)建XCTestExpectation對象
  2. 設置等待時間
    [self waitForExpectations:@[exp] timeout:0.5];
  3. 在計算完成時調用 fulfill荡灾。
    如果在規(guī)定時間內沒有調用就算超時會報錯瓤狐。
image

然后測試他執(zhí)行100萬次瞬铸,需要時間是否大于0.5秒。
顯然不可以础锐。(實測 1 秒多)

6嗓节、耦合測試

在現實項目中我們需要測試的案例肯定比以上所列舉內容要復雜。例如下舉例說明:如圖我們有一個計算 班級有多少人英語成績達到優(yōu)秀的算法皆警。

image

這個方法又是依賴與另一個工具類如下拦宣。

image

如果我們直接測試 優(yōu)秀英語學生數量的方法,是不行的信姓。因為我們創(chuàng)建的測試對象 他并沒有為 tool 初始化鸵隧。如圖所示:

image

那我們怎么解決這個問題呢。這個時候我們就需要 mock 和 stub 意推。簡單理解

  • Mock 泛指模擬的類
  • Stub 泛指模擬類的方法

那我們直接使用XCTest Mock 不就好了嗎豆瘫,結果是失望的,他并沒有為我們提供Mock功能菊值。 所以就需要我們去選擇一些適合的第三方外驱。

下文會舉案例介紹育灸,并提供demo。

4昵宇、單元測試框架選擇

1磅崭、行為驅動開發(fā)(BDD) 和 Kiwi框架 介紹

demo下載

KiwiBDD所說做到了 通過用自然語言書寫非程序員可讀的測試用例
例: 如圖我們有一個Student類,并需要測試瓦哎。

image

使用kiwi測試代碼如下


image

內容很容易理解砸喻,就和在講故事一樣。

  1. 在所有開始之前我們需要一個stu對象
  2. 在所有之后我們需要銷毀測試對象
  3. 這個學生對象應該有名字
  4. 這個學生對象應該有所有科目有分數
  5. 他應該有總分杭煎,并且計算正確

這樣一個流程恩够,就是一個完成的測試流程。在測試過程中如果哪個環(huán)節(jié)出錯了羡铲,一目了然蜂桶。

2、測試驅動開發(fā)(TDD) XCTest+OCMock

demo下載

測試驅動思想在第一章已經介紹過了也切,在這里就直接說案例了扑媚。

因為XCTestXcode深度集成,這也是很多人選擇TDD雷恃,避免第三方的集成疆股。在有需要的情況下在集成OCMock

在第三章第六節(jié)預留了一個問題倒槐。使用Mock和Stub解決測試 優(yōu)秀英語學生數量的方法的問題旬痹。如下圖當我們集成過OCMock之后

image

和之前對比,我們做的操作基本可以列成三部

  1. Mock一個Student對象
  2. Mock一個StudentTool對象讨越,并驗證
  3. 幫Mock的StudentTool置換給Studenttool并驗證

這樣我們便可以完成優(yōu)秀英語學生數量方法的測試两残。

由上我們可以看出一個問題,有依賴的方法是不方便與測試的把跨。所以說單元測試也是一種設計行為人弓,為了可以讓代碼得到優(yōu)質的測試環(huán)境,我們就會去寫一個優(yōu)質着逐,低耦合崔赌,邏輯清晰的代碼。這也是TDD的意義所在耸别。

3健芭、方案對比

由上文所說,似乎各有優(yōu)點秀姐,使用類似Kiwi框架的BDD一個是以講故事的形式來寫測試用例慈迈。使用XCTest + OCMockTDD可以讓程序員寫出更好的代碼。那么他們是否有自的缺點呢囊扳。如下圖所示:

image

顯而易見吩翻,TDD 更占優(yōu)勢兜看。在我們不集成第三方的情況XCTest也能供我們編寫測試案例。
并且當你嘗試去寫Kiwi的時候狭瞎,你會發(fā)現Kiwi在未完全執(zhí)行所有測試用例時细移,是無法看到單個測試方法的,更無法執(zhí)行單個測試熊锭。Kiwi的最小測試單位為一個測試用例類弧轧,而XCTest的最小測試單位為測試用例類的一個測試方法。

那么既然XCTest+OCMock這么好碗殷,別的第三方在寫測試用例的時候也都是這么選擇的嗎 精绎? 如圖

image

總結我認為 XCTest+OCMock是更好的選擇。


參考文獻:

XCTest apple 文檔

單元測試入門和配置

iOS單元測試初探以及OCMock使用入門

單元測試和OCMock

kiwi 實踐

Kiwi 進階

單元測試實戰(zhàn)經驗

單元測試框架選型

更新中···
武漢加油锌妻,中國加油代乃。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仿粹,隨后出現的幾起案子搁吓,更是在濱河造成了極大的恐慌,老刑警劉巖吭历,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堕仔,死亡現場離奇詭異,居然都是意外死亡晌区,警方通過查閱死者的電腦和手機摩骨,發(fā)現死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗若,“玉大人恼五,你說我怎么就攤上這事〖衿” “怎么了唤冈?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵峡迷,是天一觀的道長银伟。 經常有香客問我,道長绘搞,這世上最難降的妖魔是什么彤避? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮夯辖,結果婚禮上琉预,老公的妹妹穿的比我還像新娘。我一直安慰自己蒿褂,他們只是感情好圆米,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布卒暂。 她就那樣靜靜地躺著,像睡著了一般娄帖。 火紅的嫁衣襯著肌膚如雪也祠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天近速,我揣著相機與錄音诈嘿,去河邊找鬼。 笑死削葱,一個胖子當著我的面吹牛奖亚,可吹牛的內容都是我干的。 我是一名探鬼主播析砸,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昔字,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了首繁?” 一聲冷哼從身側響起李滴,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛮瞄,沒想到半個月后所坯,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡挂捅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年芹助,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闲先。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡状土,死狀恐怖,靈堂內的尸體忽然破棺而出伺糠,到底是詐尸還是另有隱情蒙谓,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布训桶,位于F島的核電站累驮,受9級特大地震影響,放射性物質發(fā)生泄漏舵揭。R本人自食惡果不足惜谤专,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望午绳。 院中可真熱鬧置侍,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至秕衙,卻和暖如春抬伺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灾梦。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工峡钓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留若河,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像膏燕,于是被迫代替她去往敵國和親坝辫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容