ios 單元測試

一、簡介

單元測試(Unit Testing) 是一種軟件測試方法殖卑,主要用于確定各個獨立的軟件模塊是否正確孵稽。在這個過程中菩鲜,開發(fā)者會對函數(shù)睦袖、程序或方法進行詳細的檢查以確保它們能夠按預(yù)期運行馅笙。

單元測試通常由軟件開發(fā)人員自己編寫,他們將確認具體功能是否按照設(shè)計要求正常工作皿淋。單元測試的目標是隔離代碼的每個部分窝趣,并確保每個獨立的部分都能正常工作哑舒。

例如洗鸵,如果你有一個計算器應(yīng)用程序膘滨,你可能會為加法火邓、減法蹈矮、乘法和除法等每個功能編寫單元測試,以確保當給定特定輸入時踊东,這些功能能返回正確的結(jié)果刚操。

這種測試方法可以幫助找出代碼中的錯誤和問題闸翅,確保在整個軟件系統(tǒng)中的各個單位都能正常工作措近,從而提高了代碼質(zhì)量和可維護性兼蜈。

在 iOS 開發(fā)中 XCTestApple 提供的官方測試框架蔽午,用于進行單元測試父能、性能測試以及用戶界面測試碳抄。

以下是關(guān)于 XCTest 的詳細介紹:

  • 主要組件XCTest 框架包括 XCTests(單元測試)痊夭、XCUItests(用戶界面測試)和 XCPPerformanceTests(性能測試)旱捧。
  • 單元測試(XCTests:這是最基礎(chǔ)的測試類型构捡,主要用于測試應(yīng)用中的個別方法或計算邏輯是否按預(yù)期工作液南。
  • 用戶界面測試(XCUItests:這種測試模擬用戶與應(yīng)用程序的交互操作,例如點擊按鈕勾徽、滑動屏幕等滑凉。該測試可確保當用戶使用您的應(yīng)用時,界面和交互功能能正常運行喘帚。
  • 性能測試(XCPPerformanceTests:這種測試幫助您量化代碼的性能畅姊,并在代碼更改后跟蹤其變化。您可以為某些任務(wù)設(shè)置基準時間吹由,然后在優(yōu)化代碼后比較新的執(zhí)行時間若未。
  • 測試斷言XCTest 提供了一套斷言供你驗證測試結(jié)果。這些斷言包括 XCTAssertTrue(), XCTAssertFalse(),XCTAssertEqual() 等溉知。
  • 集成和運行XCTest 完全集成在 Xcode 中陨瘩,且易于使用腕够。你可以直接從 Xcode 的測試導(dǎo)航器運行測試,或者使用快捷鍵 Cmd + U 運行所有測試舌劳。
  • 測試報告Xcode 會為執(zhí)行的 XCTest 測試生成詳細的測試報告帚湘,包括每個測試的運行時間以及哪些測試通過了,哪些失敗了甚淡。

總的來說大诸,XCTest 是一個強大的工具,能夠幫助 iOS 開發(fā)者確保他們的應(yīng)用在各種情況下都可以正常工作贯卦。

二资柔、如何項目中添加 XCTest

Xcode 中添加一個新的 XCTest 單元測試模塊相對簡單。下面是具體的步驟:

1撵割、創(chuàng)建項目是直接創(chuàng)建

2023-12-07-16-20-05-image.png

創(chuàng)建項目成功過項目目錄下即可看到對應(yīng)的單元測試文件夾

2023-12-07-16-21-54-image.png

帶有 Tests 后綴的文件夾

2贿堰、已有的項目添加 XCTest

2023-12-07-16-24-23-image.png
2023-12-07-16-25-17-image.png
2023-12-07-17-09-54-image.png

3、運行 - (void)testExample 方法一直報錯 Test Failed 啡彬。

報錯 The bundle “...Tests” couldn’t be loaded. Try reinstalling the bundle.

需要設(shè)置 team 和 項目的 team 一致來解決

image.png

4羹与、'XCTest/XCTest.h' file not found

問題描述:fatal error: 'XCTest/XCTest.h' file not found

解決方法

在報錯的 Target 中的 Building settingsFRAMEWORK_SEARCH_PATHS 添加 $(PLATFORM_DIR)/Developer/Library/Frameworks

5、運行項目報錯 Library not loaded: @rpath/XCTest.framework/XCTest

image.png

三庶灿、 XCTest 簡單使用

方法簡單概述:
setUp 方法是當前測試類的初始化方法纵搁,我們可以將一些資源準備工作在這個方法中完成;
tearDown 方式在測試結(jié)束后會調(diào)用往踢,用來進行資源的清理腾誉。
測試函數(shù)都需要以 text 開頭,testExample 是默認生成的一個測試用例函數(shù)峻呕,可以編輯testXXX方法利职,只要是 test開頭的方法都可以進行檢查。xCTest 框架提供了眾多測試斷言山上,可以用來測試眼耀,命中斷言,則認為當前測試用例失敗佩憾。
testPerformanceExample 是性能測試的一個案例哮伟,其內(nèi)的 measureBlock 里的代碼會被默認執(zhí)行10次,最終輸出每次執(zhí)行的時間消耗報告妄帘。

示例

1.測試函數(shù)的要求是:1.必須無返回值楞黄;2.實例方法要求:沒有入?yún)ⅲ瑳]有返回值抡驼,以 test 開頭鬼廓。

2.測試函數(shù)執(zhí)行的順序:以函數(shù)名中 test 后面的字符大小有關(guān),比如 -(void)test001XXX 會先于 -(void)test002XXX 執(zhí)行致盟;

3.運行單元測試的快捷鍵:CMD + U;

4.下面一共18個斷言(SDK中也是18個碎税,其含義轉(zhuǎn)自 ios UnitTest 學習筆記尤慰,真心佩服原文的博主):

`XCTFail(format…)` 生成一個失敗的測試; 

`XCTAssertNil(a1, format...)` 為空判斷雷蹂,a1為空時通過伟端,反之不通過; 

`XCTAssertNotNil(a1, format…)` 不為空判斷匪煌,a1不為空時通過责蝠,反之不通過;

`XCTAssert(expression, format...)` 當 `expression` 求值為 `TRUE` 時通過萎庭; 

`XCTAssertTrue(expression, format...)` 當 `expression` 求值為 `TRUE` 時通過霜医; 

`XCTAssertFalse(expression, format...)` 當 `expression` 求值為 `False` 時通過; 

`XCTAssertEqualObjects(a1, a2, format...)` 判斷相等驳规, `[a1 isEqual:a2]` 值為TRUE時通過肴敛,其中一個不為空時,不通過达舒;

`XCTAssertNotEqualObjects(a1, a2, format...)` 判斷不等值朋, `[a1 isEqual:a2]` 值為 `False` 時通過;

`XCTAssertEqual(a1, a2, format...)` 判斷相等(當a1和a2是 C語言標量巩搏、結(jié)構(gòu)體或聯(lián)合體時使用,實際測試發(fā)現(xiàn) `NSString` 也可以); 

`XCTAssertNotEqual(a1, a2, format...)` 判斷不等(當a1和a2是 C語言標量趾代、結(jié)構(gòu)體或聯(lián)合體時使用)贯底;

`XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)` 判斷相等,(`double`或`float`類型)提供一個誤差范圍撒强,當在誤差范圍(`+/-accuracy`)以內(nèi)相等時通過測試禽捆; 

`XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...)` 判斷不等,(`double`或`float`類型)提供一個誤差范圍飘哨,當在誤差范圍以內(nèi)不等時通過測試胚想; 

`XCTAssertThrows(expression, format...)` 異常測試,當 `expression` 發(fā)生異常時通過芽隆;反之不通過浊服;(很變態(tài)) 

`XCTAssertThrowsSpecific(expression, specificException, format...)` 異常測試,當 `expression` 發(fā)生 `specificException` 異常時通過胚吁;反之發(fā)生其他異逞捞桑或不發(fā)生異常均不通過; 

`XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)` 異常測試腕扶,當 `expression` 發(fā)生具體異常孽拷、具體異常名稱的異常時通過測試,反之不通過半抱; 

`XCTAssertNoThrow(expression, format…)` 異常測試脓恕,當 `expression` 沒有發(fā)生異常時通過測試膜宋;

`XCTAssertNoThrowSpecific(expression, specificException, format...)` 異常測試,當 `expression` 沒有發(fā)生具體異常炼幔、具體異常名稱的異常時通過測試秋茫,反之不通過; 

`XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)` 異常測試江掩,當 `expression` 沒有發(fā)生具體異常学辱、具體異常名稱的異常時通過測試,反之不通過

特別注意下 XCTAssertEqualObjectsXCTAssertEqual环形。

`XCTAssertEqualObjects(a1, a2, format...)` 的判斷條件是 `[a1 isEqual:a2]` 是否返回一個 `YES`策泣。

`XCTAssertEqual(a1, a2, format...)` 的判斷條件是`a1 == a2`是否返回一個 `YES`。

對于后者抬吟,如果a1和a2都是基本數(shù)據(jù)類型變量萨咕,那么只有a1 == a2才會返回YES。例如下面代碼中只有第二行可以通過測試:

// 1.比較基本數(shù)據(jù)類型變量
XCTAssertEqual(1, 2, @"a1 = a2 shoud be true"); // 無法通過測試
XCTAssertEqual(1, 1, @"a1 = a2 shoud be true"); // 通過測試

但是火本,如果a1和a2都是指針危队,那么只有a1和a2指向同一個對象才會返回YES。例如下面的代碼中:

    // 3.比較NSArray對象
    NSArray *array1 = @[@1];
    NSArray *array2 = @[@1];
    NSArray *array3 = array1;
    XCTAssertEqual(array1, array2, @"a1 and a2 should point to the same object"); // 無法通過測試
    XCTAssertEqual(array1, array3, @"a1 and a2 should point to the same object"); // 通過測試

array1和array2指向不同對象钙畔,無法通過測試茫陆。

這里比較奇怪的是,NSString 另當別論:

    // 2.比較NSString對象
    NSString *str1 = @"1";
    NSString *str2 = @"1";
    NSString *str3 = str1;
    XCTAssertEqual(str1, str2, @"a1 and a2 should point to the same object"); // 通過測試
    XCTAssertEqual(str1, str3, @"a1 and a2 should point to the same object"); // 通過測試

盡管str1和str2指向不同的對象擎析,但是二者的指針比較卻能通過測試簿盅。
由于str1和str2指向同一常量,常量在內(nèi)存的 data 段中地址是固定的揍魂,所以二者地址相同桨醋。

四、異步函數(shù)的測試

前面我們演示的測試用例所執(zhí)行的邏輯都是同步的现斋,但在實際的項目中喜最,異步的操作很多,XCTest框架中也提供了異步邏輯的測試方式庄蹋。例如對如下業(yè)務(wù)方法進行測試:

- (void)requestData:(void (^)(BOOL))complete {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (complete) {
            complete(YES);
        }
    });
}

測試用例如下:

- (void)testAsync {
    XCTestExpectation *except = [self expectationWithDescription:@"異步請求測試用例"];
    [self.viewModel requestData:^(BOOL success) {
        XCTAssertTrue(success);
        [except fulfill];
    }];
    [self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
        
    }];
}

XCTestExpectation 可以理解為一個期望對象瞬内,當使用此對象調(diào)用 fulfill 方法后,表示異步邏輯完成蔓肯。

五遂鹊、代碼覆蓋率

與單元測試相關(guān)的,還有一個重要的概念:代碼覆蓋率蔗包。代碼覆蓋率是指在整個測試執(zhí)行過程中秉扑,覆蓋到的功能函數(shù)與所有功能函數(shù)的比例。覆蓋率越高說明測試涉及的功能越全。

測試完成后舟陆,可以直接在Xcode中查看代碼覆蓋率误澳,如下圖所示:

image.png

單元測試保持較高的覆蓋率是非常重要的,其從另一個方面也是測試質(zhì)量的保障秦躯。【當然這里是一個示例忆谓,所以沒有很高的覆蓋率】

如果看不到代碼覆蓋率,點擊edit scheme,看對應(yīng)的tagart-->test-->code Coverage 那個對勾都勾上了沒有

image.png

六踱承、關(guān)于單元測試(邏輯代碼部分)的幾點建議

不涉及UI方面的自動化測試倡缠,只針對邏輯代碼的單元測試,下面這些建議可供參考:

  • 在編碼時茎活,要盡量按照MVVM的模式進行開發(fā)昙沦,相比MVC模式,MVVM的邏輯代碼都封裝在VM里面载荔,更利于進行脫離UI的測試盾饮。可以設(shè)想懒熙,如果將邏輯方法都寫在ViewViewController中丘损,則執(zhí)行測試用例時就不得不引入很多額外的頁面UI組件。

  • 編寫測試用例時工扎,有3個核心要考慮的點徘钥,即輸入輸出結(jié)果判定肢娘。我們通過輸入來設(shè)置測試用例的初始狀態(tài)吏饿,通過對輸出的結(jié)果判定來決定測試用例是否通過。

  • 在開發(fā)中蔬浙,編寫的函數(shù)要盡量符合下面的特性:功能單一,有輸入有輸出贞远。

  • 函數(shù)有輸入?yún)?shù)畴博,沒有返回值時,需要對輸入的參數(shù)進行修改蓝仲,則這種場景編寫測試用例時俱病,要判斷的是執(zhí)行函數(shù)操作后的原始變量是否符合預(yù)期。

  • 函數(shù)沒有輸入?yún)?shù)袱结,沒有返回值時亮隙,其作用只是執(zhí)行一段邏輯操作,例如存儲文件垢夹,修改文件等溢吻。這時我們可以修改下功能函數(shù),在函數(shù)內(nèi)返回操作成功或失敗的結(jié)果,測試用例使用此結(jié)果來作為是否通過的標準促王。

七犀盟、XCTest 框架中也是有 UI 測試的

例如: 創(chuàng)建一個 UI Test Target

image.png
image.png

自帶會有這樣的方法測試啟動時長性能方法

生成文件示例


image.png

運行查看啟動時長

image.png

啟動時長日志輸出

image.png

總結(jié):默認會聯(lián)系多次啟動,可以查看每次的時長蝇狼,方便對比結(jié)果阅畴。

遇到的 UITest 問題
testExample: Device is not configured for UI testing - use of XCUIApplication is not supported. This can happen when XCUIApplication is used in a unit test bundle instead of a UI test bundle. (NSInternalInconsistencyException)

解決方案: 1、UI test 和 邏輯 test 是不同的 target迅耘, 可能選擇錯了贱枣,需要創(chuàng)建 UI test target

image.png
image.png

更多的使用可以參考iOS單元測試的那些事兒

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市颤专,隨后出現(xiàn)的幾起案子纽哥,更是在濱河造成了極大的恐慌,老刑警劉巖血公,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昵仅,死亡現(xiàn)場離奇詭異,居然都是意外死亡累魔,警方通過查閱死者的電腦和手機摔笤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垦写,“玉大人吕世,你說我怎么就攤上這事√萃叮” “怎么了命辖?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長分蓖。 經(jīng)常有香客問我尔艇,道長,這世上最難降的妖魔是什么么鹤? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任终娃,我火速辦了婚禮,結(jié)果婚禮上蒸甜,老公的妹妹穿的比我還像新娘棠耕。我一直安慰自己,他們只是感情好柠新,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布窍荧。 她就那樣靜靜地躺著,像睡著了一般恨憎。 火紅的嫁衣襯著肌膚如雪蕊退。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音咕痛,去河邊找鬼痢甘。 笑死,一個胖子當著我的面吹牛茉贡,可吹牛的內(nèi)容都是我干的塞栅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼腔丧,長吁一口氣:“原來是場噩夢啊……” “哼放椰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起愉粤,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤砾医,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后衣厘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體如蚜,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年影暴,在試婚紗的時候發(fā)現(xiàn)自己被綠了错邦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡型宙,死狀恐怖撬呢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妆兑,我是刑警寧澤魂拦,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站搁嗓,受9級特大地震影響芯勘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腺逛,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一借尿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屉来,春花似錦、人聲如沸狈癞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝶桶。三九已至慨绳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脐雪。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工厌小, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人战秋。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓璧亚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脂信。 傳聞我的和親對象是個殘疾皇子癣蟋,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容