前言
單元測(cè)試和UI測(cè)試大致步驟網(wǎng)上很多文章都有,如果會(huì)的可以忽略,關(guān)鍵是錯(cuò)誤總結(jié),網(wǎng)上很少有文章提及到,感興趣的讀者可以拉到最后面看看總結(jié),相信你一定有所收獲!!!
unitTests測(cè)試
1.unitTests作用
由于只是一些簡(jiǎn)單實(shí)用的東西,學(xué)學(xué)還是挺不錯(cuò)的。其實(shí)單元測(cè)試用的好,開發(fā)起來也會(huì)快很多。單元測(cè)試對(duì)于我目前來說,就是為了方便測(cè)試一些功能是否正常運(yùn)行,還有調(diào)試接口是否能正常使用。有時(shí)候你可能是為了測(cè)試某一個(gè)網(wǎng)絡(luò)接口,然后每次都重新啟動(dòng)并且經(jīng)過很多操作之后才測(cè)試到了那個(gè)網(wǎng)絡(luò)接口。如果使用了單元測(cè)試,就可以直接測(cè)試那個(gè)方法,相對(duì)方便很多。 比如由于修改較多,我們想測(cè)試一下分享功能是否正常,這時(shí)候就有用了。(而不是重新啟動(dòng)程序,進(jìn)入到分享界面,點(diǎn)擊分享,填寫分享內(nèi)容。)其實(shí)單元測(cè)試并沒有降低我們打代碼的效率,我們可以在單元測(cè)試通過了,直接用到相應(yīng)的地方。
當(dāng)然也有一些高級(jí)的作用,比如自動(dòng)發(fā)布、自動(dòng)測(cè)試(特別在一些大的項(xiàng)目,以防止程序被誤改或引起新的問題)。
現(xiàn)在,讓我們先理清一下單元測(cè)試到底有些什么東西?
OCUnit(即用XCTest進(jìn)行測(cè)試)其實(shí)就是蘋果自帶的測(cè)試框架,我們主要講的就是這個(gè)。GHUnit是一個(gè)可視化的測(cè)試框架。(有了它,你可以點(diǎn)擊APP來決定測(cè)試哪個(gè)方法,并且可以點(diǎn)擊查看測(cè)試結(jié)果等。)OCMock就是模擬某個(gè)方法或者屬性的返回值,你可能會(huì)疑惑為什么要這樣做?使用用模型生成的模型對(duì)象,再傳進(jìn)去不就可以了?答案是可以的,但是有特殊的情況。比如你測(cè)試的是方法A,方法A里面調(diào)用到了方法B,而且方法B是有參數(shù)傳入,但又不是方法A所提供。這時(shí)候,你可以使用OCMock來模擬方法B返回的值。(在不影響測(cè)試的情況下,就可以這樣去模擬。)除了這些,在沒有網(wǎng)絡(luò)的情況下,也可以通過OCMock模擬返回的數(shù)據(jù)。UITests就是通過代碼化來實(shí)現(xiàn)自動(dòng)點(diǎn)擊界面,輸入文字等功能。靠人工操作的方式來覆蓋所有測(cè)試用例是非常困難的,尤其是加入新功能以后,舊的功能也要重新測(cè)試一遍,這導(dǎo)致了測(cè)試需要花非常多的時(shí)間來進(jìn)行回歸測(cè)試,這里產(chǎn)生了大量重復(fù)的工作,而這些重復(fù)的工作有些是可以自動(dòng)完成的,這時(shí)候UITests就可以幫助解決這個(gè)問題了。
2.unitTests的使用
創(chuàng)建一個(gè)工程,名字隨便取,直接勾選include Unit Tests
萬一我忘了勾選怎么辦呢?可以有其他方式創(chuàng)建File-->new-->target-->iOS-->iOS Unit Testing Bundle。名字自己看著辦吧。
工程創(chuàng)建好后,那要怎么開始測(cè)試呢?
找到系統(tǒng)單元測(cè)試Testes文件夾中.m文件看中會(huì)到看到幾個(gè)方法,我們來看下這個(gè)幾個(gè)方法是什么時(shí)候調(diào)用和他們各種的作用
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
//初始化的代碼,在測(cè)試方法調(diào)用之前調(diào)用
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
// 釋放測(cè)試用例的資源代碼,這個(gè)方法會(huì)每個(gè)測(cè)試用例執(zhí)行后調(diào)用
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// 測(cè)試用例的例子,注意測(cè)試用例一定要test開頭
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
// 測(cè)試性能例子
[self measureBlock:^{
// Put the code you want to measure the time of here.
// 需要測(cè)試性能的代碼
}];
}
在ViewController中寫一個(gè)簡(jiǎn)單的方法
-(int)getNum;
實(shí)現(xiàn):
- (int)getNum {
return 100;
}
在測(cè)試的文件中導(dǎo)入ViewController.h,并且定義一個(gè)vc屬性
#import
#import "ViewController.h"
@interface ____Tests : XCTestCase
@property (nonatomic,strong) ViewController *vc;
@end
@implementation ____Tests
//測(cè)試用例的實(shí)現(xiàn)
- (void)setUp {
[super setUp];
// 實(shí)例化需要測(cè)試的類
self.vc = [[ViewController alloc] init];
}
- (void)tearDown {
// 清空
self.vc = nil;
[super tearDown];
}
- (void)testMyFuc {
// 調(diào)用需要測(cè)試的方法,
int result = [self.vc getNum];
// 如果不相等則會(huì)提示@“測(cè)試不通過”
XCTAssertEqual(result, 100,@"測(cè)試不通過");
}
command+u快捷方式運(yùn)行,或者produce-->test都行,或只跑某個(gè)測(cè)試用例如圖
性能測(cè)試
3.使用的斷言種類
1.XCTFail(format…) 生成一個(gè)失敗的測(cè)試;
2.XCTAssertNil(a1, format...)為空判斷,a1為空時(shí)通過,反之不通過;
3.XCTAssertNotNil(a1, format…)不為空判斷,a1不為空時(shí)通過,反之不通過;
4.XCTAssert(expression, format...)當(dāng)expression求值為TRUE時(shí)通過;
5.XCTAssertTrue(expression, format...)當(dāng)expression求值為TRUE時(shí)通過;
6.XCTAssertFalse(expression, format...)當(dāng)expression求值為False時(shí)通過;
7.XCTAssertEqualObjects(a1, a2, format...)判斷相等,[a1 isEqual:a2]值為TRUE時(shí)通過,其中一個(gè)不為空時(shí),不通過;
8.XCTAssertNotEqualObjects(a1, a2, format...)判斷不等,[a1 isEqual:a2]值為False時(shí)通過;
9.XCTAssertEqual(a1, a2, format...)判斷相等(當(dāng)a1和a2是 C語言標(biāo)量、結(jié)構(gòu)體或聯(lián)合體時(shí)使用,實(shí)際測(cè)試發(fā)現(xiàn)NSString也可以);
10.XCTAssertNotEqual(a1, a2, format...)判斷不等(當(dāng)a1和a2是 C語言標(biāo)量、結(jié)構(gòu)體或聯(lián)合體時(shí)使用);
11.XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)判斷相等,(double或float類型)提供一個(gè)誤差范圍,當(dāng)在誤差范圍(+/-accuracy)以內(nèi)相等時(shí)通過測(cè)試;
12.XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...) 判斷不等,(double或float類型)提供一個(gè)誤差范圍,當(dāng)在誤差范圍以內(nèi)不等時(shí)通過測(cè)試;
13.XCTAssertThrows(expression, format...)異常測(cè)試,當(dāng)expression發(fā)生異常時(shí)通過;反之不通過;(很變態(tài))
14.XCTAssertThrowsSpecific(expression, specificException, format...) 異常測(cè)試,當(dāng)expression發(fā)生specificException異常時(shí)通過;反之發(fā)生其他異常或不發(fā)生異常均不通過;
15.XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)異常測(cè)試,當(dāng)expression發(fā)生具體異常、具體異常名稱的異常時(shí)通過測(cè)試,反之不通過;
16.XCTAssertNoThrow(expression, format…)異常測(cè)試,當(dāng)expression沒有發(fā)生異常時(shí)通過測(cè)試;
17.XCTAssertNoThrowSpecific(expression, specificException, format...)異常測(cè)試,當(dāng)expression沒有發(fā)生具體異常、具體異常名稱的異常時(shí)通過測(cè)試,反之不通過;
18.XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)異常測(cè)試,當(dāng)expression沒有發(fā)生具體異常、具體異常名稱的異常時(shí)通過測(cè)試,反之不通過
特別注意下XCTAssertEqualObjects和XCTAssertEqual。
XCTAssertEqualObjects(a1, a2, format...)的判斷條件是[a1 isEqual:a2]是否返回一個(gè)YES。
XCTAssertEqual(a1, a2, format...)的判斷條件是a1 == a2是否返回一個(gè)YES。
對(duì)于后者,如果a1和a2都是基本數(shù)據(jù)類型變量,那么只有a1 == a2才會(huì)返回YES。
4.異步函數(shù)的單元測(cè)試
//waitForExpectationsWithTimeout是等待時(shí)間,超過了就不再等待往下執(zhí)行。
#define WAIT do {\
[self expectationForNotification:@"RSBaseTest" object:nil handler:nil];\
[self waitForExpectationsWithTimeout:30 handler:nil];\
} while (0);
#define NOTIFY \
[[NSNotificationCenter defaultCenter]postNotificationName:@"RSBaseTest" object:nil];
增加測(cè)試方法testRequest:
-(void)testRequest{
// 1.獲得請(qǐng)求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",nil];
// 2.發(fā)送GET請(qǐng)求
[mgr GET:@"http://www.weather.com.cn/adat/sk/101110101.html" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"responseObject:%@",responseObject);
XCTAssertNotNil(responseObject, @"返回出錯(cuò)");
NOTIFY //繼續(xù)執(zhí)行
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"error:%@",error);
XCTAssertNil(error, @"請(qǐng)求出錯(cuò)");
NOTIFY //繼續(xù)執(zhí)行
}];
WAIT//暫停
}
5.測(cè)試覆蓋率的查看
在運(yùn)行測(cè)試之前,我們必須先確認(rèn) code coverage 是否被打開了,寫代碼時(shí),默認(rèn)是關(guān)閉的。所以你需要編輯一下你的測(cè)試 scheme,把它打開。
確保"Gather coverage data"是被選中的,然后點(diǎn)擊關(guān)閉按鈕,運(yùn)行測(cè)試的 target. 我們希望剛剛創(chuàng)建的測(cè)試用例能夠順利通過。
Coverage Tab
一旦這個(gè)測(cè)試通過了,你就能知道 checkWord 這個(gè)方法,至少有一條路徑是對(duì)的。但你不知道的是,還多多少?zèng)]有被測(cè)試到。這就是code coverage這個(gè)工具的好處。當(dāng)你打開code coverage tab后,你可以清楚的看到測(cè)試的覆蓋情況。他們按找 target, file, function 進(jìn)行了自動(dòng)分組。
打開Xcode左邊窗口的Report Navigator面板,選中你剛運(yùn)行的測(cè)試。然后在tab中選中 Coverage。
這會(huì)展示一個(gè)你的類、方法的列表,并標(biāo)示出每個(gè)的測(cè)試覆蓋率。如果你將鼠標(biāo)懸停在checkWord這個(gè)方法上,你可以看到測(cè)試的覆蓋率是28%。不能接受啊!我們需要找到,那些代碼分支是能夠被測(cè)試執(zhí)行,那些是不能的,進(jìn)而改善他們。雙擊方法的名字,Xcode會(huì)打開類的代碼,并且看到code coverage的情況。
白色的區(qū)域表示這些代碼時(shí)測(cè)試覆蓋過的。灰色區(qū)域時(shí)測(cè)試無法覆蓋的,我們需要添加更多的測(cè)試用例來覆蓋灰色部分的代碼。在右手邊的數(shù)字,表明這些代碼塊,在這次測(cè)試中被執(zhí)行的次數(shù)。
UI測(cè)試
?可以參考這個(gè)網(wǎng)站?http://www.cocoachina.com/ios/20150702/12253.html 這里就不啰嗦了
總結(jié)UI測(cè)試遇到的問題 (重點(diǎn))?
1.自動(dòng)生成uitests字符亂碼問題
目前查閱資料只有\(zhòng)U變成\u,可以用查找工具替換掉,生成的unicode編碼也可以直接用中文替換;
2.uitests自動(dòng)生成的代碼經(jīng)常報(bào)TimeStamped Event Matching Error:Failed to find matching element ,這個(gè)大多數(shù)原因是由于控件id變化導(dǎo)致的,所以對(duì)于id動(dòng)態(tài)變化一般都通過下標(biāo)形式查找到相應(yīng)的控件
Xcode自動(dòng)產(chǎn)生的大多數(shù)是這樣:
[app.buttons[@"\u4e8c\u624b\u8f66\u4e16\u754c"] tap];
Demo:
[[[[[app.tables elementBoundByIndex:0] childrenMatchingType:XCUIElementTypeCell] elementBoundByIndex:4] childrenMatchingType:XCUIElementTypeTextField] elementBoundByIndex:0]
[app.XXX];獲得當(dāng)前window上所有這種類型的控件
3.uitests textFiled不能通過identifier直接獲取到,利用錄制的話一般以點(diǎn)擊就會(huì)報(bào)錯(cuò)誤;
4.descendantsMatchingType查找包含子類,childrenMatchingType查找本類不包含子類;
5.獲取的控件不知道存不存在時(shí)可以用exists判斷下,對(duì)沒有獲取到的控件操作直接會(huì)崩;
6.要特別注意彈出的視圖,如果此時(shí)對(duì)后面一層視圖操作會(huì)出問題,如果能自動(dòng)消失的,可以使用延遲pressForDuration: (NSTimeInterval)后在操作,如果不會(huì)消失的要轉(zhuǎn)到這層操作;
7.Assertion Failure: :0: UI Testing Failure - Failed to scroll to visible (by AX action) Image 0x600000175240: traits: 8589934596, {{172.0, 70.0}, {70.0, 70.0}}, identifier: 'Icon_Boy', error: Error -25204 performing AXAction 2003 //沒有滾到可見范圍的錯(cuò)誤
[[[[[self.app.tables elementBoundByIndex:0] descendantsMatchingType:XCUIElementTypeAny] elementBoundByIndex:0]tap]; 報(bào)上面的錯(cuò)誤
解決:[[[[[self.app.tables elementBoundByIndex:0] descendantsMatchingType:XCUIElementTypeAny] elementBoundByIndex:0] coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)] tap];
coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5) 使用這個(gè)函數(shù)增加點(diǎn)偏移量即可,我試了0.5,0.5 可以用,你們可以試試別的行不行,目前我還不知道這個(gè)值是怎么確定的,我們需要做判斷用這個(gè)方法時(shí),可以用isHittable這個(gè)判斷下是否可以點(diǎn)擊,如果是false,就用偏移的方法,如果返回為yes,就原來的方法即可
有時(shí)候放在tableview頭視圖的imageView,使用[[self.app.images elementBoundByIndex:0] tap]產(chǎn)生這種錯(cuò)誤時(shí),可以使用[[self.app.tables elementBoundByIndex:0] descendantsMatchingType:XCUIElementTypeAny] elementBoundByIndex:0] tap]解決
有任何問題可以@我哦
參考網(wǎng)址
http://www.lxweimin.com/p/009844a0b9edUnitTest(簡(jiǎn)單的單元測(cè)試使用)
http://blog.csdn.net/it_ds/article/details/51286791UnitTest(簡(jiǎn)單的單元測(cè)試使用)
http://www.lxweimin.com/p/8bbec078cabeUnitTest(有異步測(cè)試Demo)
http://www.lxweimin.com/p/254d6f9f0bc4UnitTest(利用GCD實(shí)現(xiàn)異步測(cè)試Demo)
http://www.cocoachina.com/ios/20150702/12253.html ? ?UITest
http://blog.sina.com.cn/s/blog_864456e50101ekqh.html斷言解釋說明
http://www.cnblogs.com/ziyi--caolu/p/4893847.htmlUnitTest(有測(cè)試實(shí)例代碼)
http://www.cocoachina.com/ios/20150915/13163.html單元測(cè)試覆蓋率
https://pan.baidu.com/s/1eR112i2自動(dòng)化測(cè)試視頻地址