ios單元測(cè)試

OCUnit(即用XCTest進(jìn)行測(cè)試
)蘋果自帶的測(cè)試框架盖奈,GHUnit是一個(gè)可視化的測(cè)試框架恶守。(有了它埋嵌,你可以點(diǎn)擊APP來(lái)決定測(cè)試哪個(gè)方法破加,并且可以點(diǎn)擊查看測(cè)試結(jié)果等。)OCMock就是模擬某個(gè)方法或者屬性的返回值莉恼,你可能會(huì)疑惑為什么要這樣做?使用用模型生成的模型對(duì)象拌喉,再傳進(jìn)去不就可以了速那?答案是可以的,但是有特殊的情況尿背。比如你測(cè)試的是方法A端仰,方法A里面調(diào)用到了方法B,而且方法B是有參數(shù)傳入田藐,但又不是方法A所提供荔烧。這時(shí)候,你可以使用OCMock來(lái)模擬方法B返回的值汽久。(在不影響測(cè)試的情況下鹤竭,就可以這樣去模擬。)除了這些景醇,在沒(méi)有網(wǎng)絡(luò)的情況下臀稚,也可以通過(guò)OCMock模擬返回的數(shù)據(jù)。UITests就是通過(guò)代碼化來(lái)實(shí)現(xiàn)自動(dòng)點(diǎn)擊界面三痰,輸入文字等功能吧寺。靠人工操作的方式來(lái)覆蓋所有測(cè)試用例是非常困難的散劫,尤其是加入新功能以后稚机,舊的功能也要重新測(cè)試一遍,這導(dǎo)致了測(cè)試需要花非常多的時(shí)間來(lái)進(jìn)行回歸測(cè)試获搏,這里產(chǎn)生了大量重復(fù)的工作赖条,而這些重復(fù)的工作有些是可以自動(dòng)完成的,這時(shí)候UITests就可以幫助解決這個(gè)問(wèn)題常熙。

先來(lái)簡(jiǎn)單的了解一下單元測(cè)試
11.png

使用快捷鍵Command+U纬乍,這個(gè)快捷鍵是全部測(cè)試。
也可以單個(gè)方法的測(cè)試:

111.jpg

表示測(cè)試通過(guò)就會(huì)出現(xiàn)綠色的菱形

222.png
熟悉單元測(cè)試類

333.png

UnitTestsDemoTests類是繼承與 XCTestCase的

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    //每個(gè)test方法執(zhí)行之前調(diào)用
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
    // 每個(gè)test方法執(zhí)行之后調(diào)用
}


- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
   // 命名為Example的測(cè)試方法
}
//性能測(cè)試
- (void)testPerformanceExample {
    // This is an example of a performance test case.
   //主要檢測(cè)代碼的執(zhí)行性能
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}

Xcode7默認(rèn)帶了測(cè)試性能的方法- (void)testPerformanceExample

- (void)testPerformanceExample { 
// This is an example of a performance test case.
 [self measureBlock:^{ 
// Put the code you want to measure the time of here. 
       for(int i=0;i<1000;i++) { 
                NSLog(@"%d",i); 
          } 
 }];
}

重復(fù)執(zhí)行上面的代碼症概,會(huì)收集每次執(zhí)行的時(shí)間蕾额,并計(jì)算出平均值,每次執(zhí)行后會(huì)跟平均值進(jìn)行比較彼城,給你參考性的提示诅蝶。

333.jpg

當(dāng)我們把i的值后面增添一個(gè)0后:

444.jpg

XCode檢測(cè)到這一次運(yùn)行,遠(yuǎn)超過(guò)了平均值募壕,給出了紅色的警告

自定義測(cè)試方法
  • 自定義測(cè)試方法必須以test方法名開(kāi)頭(testXXX)调炬,例如testExample
  • 自定義方法必須為void返回類型

斷言
大部分的測(cè)試方法使用斷言決定的測(cè)試結(jié)果。所有斷言都有一個(gè)類似的形式:比較舱馅,表達(dá)式為真假缰泡,強(qiáng)行失敗等。

//通用斷言
XCTAssert(expression, format...)
//常用斷言:
XCTAssertTrue(expression, format...)
XCTAssertFalse(expression, format...)
XCTAssertEqual(expression1, expression2, format...)
XCTAssertNotEqual(expression1, expression2, format...)
XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)
XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)
XCTAssertNil(expression, format...)
XCTAssertNotNil(expression, format...)
XCTFail(format...) //直接Fail的斷言

舉個(gè)栗子

- (void)testExample { 
//設(shè)置變量和設(shè)置預(yù)期值
  NSUInteger a = 10;
  NSUInteger b = 15; 
  NSUInteger expected = 24; 
  //執(zhí)行方法得到實(shí)際值 
  NSUInteger actual = [self add:a b:b]; 
  //斷言判定實(shí)際值和預(yù)期是否符合 
  XCTAssertEqual(expected, actual,@"add方法錯(cuò)誤!");
}
-(NSUInteger)add:(NSUInteger)a b:(NSUInteger)b{ 
return a+b;
}

從這也能看出一個(gè)測(cè)試用例比較規(guī)范的寫(xiě)法棘钞,1:定義變量和預(yù)期缠借,2:執(zhí)行方法得到實(shí)際值,3:斷言

性能測(cè)試
性能測(cè)試主要使用measureBlock
方法 宜猜,用于測(cè)試一組方法的執(zhí)行時(shí)間泼返,通過(guò)設(shè)置baseline(基準(zhǔn))和stddev(標(biāo)準(zhǔn)偏差)來(lái)判斷方法是否能通過(guò)性能測(cè)試。
舉個(gè)栗子:

- (void)testPerformanceExample { 
// This is an example of a performance test case. 
[self measureBlock:^{
 //Put the code you want to measure the time of here. 
//你的性能測(cè)試的代碼放在這里
 }];
}

直接執(zhí)行方法姨拥,因?yàn)閎lock中沒(méi)有內(nèi)容绅喉,所以方法的執(zhí)行時(shí)間為0.0s,如果我們把baseline設(shè)成0.05,偏差10%,是可以通過(guò)的測(cè)試的叫乌。但是如果設(shè)置如果我們把baseline為1柴罐,偏差10%,那測(cè)試會(huì)失敗憨奸,因?yàn)椴粷M足條件革屠。

666

異步測(cè)試
測(cè)試異步方法時(shí),因?yàn)榻Y(jié)果并不是立刻獲得膀藐,所以在異步方法測(cè)試有一些特殊的方法和技巧屠阻。

舉個(gè)栗子:

- (void)testAsynExample { 
XCTestExpectation *exp = [self expectationWithDescription:@"這里可以是操作出錯(cuò)的原因描述。额各。。"]; 
NSOperationQueue *queue = [[NSOperationQueue alloc]init]; 
[queue addOperationWithBlock:^{
 //模擬這個(gè)異步操作需要2秒后才能獲取結(jié)果吧恃,比如一個(gè)異步網(wǎng)絡(luò)請(qǐng)求 
sleep(2); 
//模擬獲取的異步操作后虾啦,獲取結(jié)果,判斷異步方法的結(jié)果是否正確 
XCTAssertEqual(@"a", @"a"); 
//如果斷言沒(méi)問(wèn)題痕寓,就調(diào)用fulfill宣布測(cè)試滿足
 [exp fulfill]; 
}]; //設(shè)置延遲多少秒后傲醉,如果沒(méi)有滿足測(cè)試條件就報(bào)錯(cuò)
 [self waitForExpectationsWithTimeout:3 handler:^(NSError * _Nullable error) { 
if (error) { 
NSLog(@"Timeout Error: %@", error); }
 }];
}

這個(gè)測(cè)試肯定是通過(guò)的,因?yàn)樵O(shè)置延遲為3秒呻率,而異步操作2秒就除了一個(gè)正確的結(jié)果硬毕,并宣布了條件滿足[exp fulfill]
,但是當(dāng)我們把延遲改成1秒礼仗,這個(gè)測(cè)試用例就不會(huì)成功吐咳,錯(cuò)誤原因是expectationWithDescription:@"這里可以是操作出錯(cuò)的原因描述。元践。韭脊。

異步測(cè)試除了使用expectationWithDescription
以外,還可以使用expectationForPredicate和expectationForNotification

下面這個(gè)例子使用expectationForPredicate
測(cè)試方法单旁,代碼來(lái)自于AFNetworking沪羔,用于測(cè)試backgroundImageForState
方法

- (void)testThatBackgroundImageChanges { 
XCTAssertNil([self.button backgroundImageForState:UIControlStateNormal]); 
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UIButton * _Nonnull button, NSDictionary<NSString *,id> * _Nullable bindings) { 
return [button backgroundImageForState:UIControlStateNormal] != nil; 
}]; 
[self expectationForPredicate:predicate evaluatedWithObject:self.button handler:nil]; 
[self waitForExpectationsWithTimeout:20 handler:nil];
}

利用謂詞計(jì)算,button是否正確的獲得了backgroundImage象浑,如果正確20秒內(nèi)正確獲得則通過(guò)測(cè)試蔫饰,否則失敗琅豆。
expectationForNotification
方法 ,該方法監(jiān)聽(tīng)一個(gè)通知,如果在規(guī)定時(shí)間內(nèi)正確收到通知?jiǎng)t測(cè)試通過(guò)。

-(void)testAsynExample1 { 
[self expectationForNotification:(@"監(jiān)聽(tīng)通知的名稱xxx") object:nil handler:nil]; 
[[NSNotificationCenter defaultCenter]postNotificationName:@"監(jiān)聽(tīng)通知的名稱xxx" object:nil]; 
//設(shè)置延遲多少秒后篓吁,如果沒(méi)有滿足測(cè)試條件就報(bào)錯(cuò)
[self waitForExpectationsWithTimeout:3 handler:nil];
}

命令行測(cè)試
測(cè)試不僅可以在xcode中執(zhí)行趋距,也可以在命令行中執(zhí)行,這個(gè)便于代碼持續(xù)集成和構(gòu)建越除,在git提交中也編譯檢查代碼

如果你有development-enabled設(shè)備插入节腐,你可以按照名稱或 id 調(diào)用他們。例如摘盆,如果你有一個(gè)名為”Development iPod touch”的 iPod 設(shè)備連接了測(cè)試的代碼翼雀,可以使用下面的命令來(lái)測(cè)試代碼> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination 'platform=iOS,name=Development iPod touch

測(cè)試也可以在 iOS模擬器上運(yùn)行。使用模擬器可以應(yīng)對(duì)不同的外形因素和操作系統(tǒng)版本孩擂。例如> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone,0S=7.0'

-destination 參數(shù)可以被連接在一起狼渊,這樣你只需使用一個(gè)命令,就可以跨目標(biāo)進(jìn)行指定集成共享方案类垦。例如狈邑,下面的命令把之前的三個(gè)例子合并到一個(gè)命令中

> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp
-destination 'platform=OS X,arch=x86_64'
-destination 'platform=iOS,name=Development iPod touch'
-destination 'platform=iOS Simulator,name=iPhone,0S=7.0'

關(guān)于更多xcodebuild的使用可以查看man手冊(cè)> man xcodebuild

執(zhí)行測(cè)試快捷鍵
cmd + 5 切換到測(cè)試選項(xiàng)卡后會(huì)看到很多小箭頭,點(diǎn)擊可以單獨(dú)或整體測(cè)試
cmd + U 運(yùn)行整個(gè)單元測(cè)試

注意點(diǎn)
使用pod的項(xiàng)目中蚤认,在XC測(cè)試框架中測(cè)試內(nèi)容包括第三方包時(shí)米苹,需要手動(dòng)去設(shè)置Header Search Paths才能找到頭文件 ,還需要設(shè)置test target的PODS_ROOT砰琢。
參考閱讀
http://www.tuicool.com/articles/jUrqiqR

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蘸嘶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子陪汽,更是在濱河造成了極大的恐慌训唱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挚冤,死亡現(xiàn)場(chǎng)離奇詭異况增,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)训挡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門澳骤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人舍哄,你說(shuō)我怎么就攤上這事宴凉∑羯希” “怎么了淋肾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵稠茂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蔼啦,道長(zhǎng)豪治,這世上最難降的妖魔是什么局齿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任养铸,我火速辦了婚禮,結(jié)果婚禮上戒悠,老公的妹妹穿的比我還像新娘熬荆。我一直安慰自己,他們只是感情好绸狐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布卤恳。 她就那樣靜靜地躺著,像睡著了一般寒矿。 火紅的嫁衣襯著肌膚如雪突琳。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天符相,我揣著相機(jī)與錄音拆融,去河邊找鬼。 笑死啊终,一個(gè)胖子當(dāng)著我的面吹牛镜豹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蓝牲,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼趟脂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了搞旭?” 一聲冷哼從身側(cè)響起散怖,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肄渗,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體咬最,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翎嫡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了永乌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惑申。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翅雏,靈堂內(nèi)的尸體忽然破棺而出圈驼,到底是詐尸還是另有隱情,我是刑警寧澤望几,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布绩脆,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏靴迫。R本人自食惡果不足惜惕味,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玉锌。 院中可真熱鬧名挥,春花似錦、人聲如沸主守。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)参淫。三九已至救湖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間黄刚,已是汗流浹背捎谨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憔维,地道東北人涛救。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像业扒,于是被迫代替她去往敵國(guó)和親检吆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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