添加測試目標: html
product scheme測試設置: node
繼承XCTestCase,默認的方法有4個:ios
測試用例命名必須以test開頭,不可有參數且返回爲void,否則沒法識別爲測試方法。測試用例類型有3種:普通測試,性能測試與異步測試。git
運行單元測試: CMD + U測試整個文件的測試用例. 也可經過每一個單元測試用例左邊的按鈕執行單元測試,執行後綠色勾選按鈕表明測試成功,紅色叉號按鈕表明測試失敗。github
#import <XCTest/XCTest.h> #import "HPUser.h" [@interface](https://my.oschina.net/u/996807) ReactiveDemoOneTests : XCTestCase //1.測試類名 [@end](https://my.oschina.net/u/567204) @implementation ReactiveDemoOneTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [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. } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } -(void)testInitializer{//2.測試實例方法前綴必須是test HPUser *user = [[HPUser alloc]init]; XCTAssert(user,@"user alloc-init fail");//3.XCTAssert方法用於斷言對象不是nil } -(void)testPropertyGetter{//4.測試屬性的獲取 HPUser *user = [[HPUser alloc]init]; user.name = @"ZJ"; user.LoginTime = [NSDate date]; ZJEntry *zj = [[ZJEntry alloc]init]; zj.vipLever = @"10"; zj.sexy = @"man"; user.zoujie = zj;//5.測試狀態前的對象設置和須要提早執行的代碼 XCTAssertEqualObjects(@"man", zj.sexy); XCTAssertEqualObjects(@"10", zj.vipLever); XCTAssertEqualObjects(@"ZJ", user.name); XCTAssertEqualObjects(user.zoujie, zj);//6.測試對象等價性的斷言 } -(void) testOne{ NSLog(@"1111111111111111"); NSInteger wordA = 1; XCTAssertTrue(wordA == 1,@"斷言wordA等於0,不等於則測試沒經過"); } -(void) testTwo{ NSLog(@"22222222222222222"); } -(void) fourMethod{ NSLog(@"wrong method444444"); } @end
參考文章:http://blog.csdn.net/Jolie_Yang/article/details/54891250數據庫
在自動化單元測試或功能測試中,使用代碼覆蓋率來表示通過測試的代碼的百分比。 1.集成覆蓋率報告 開啓測試覆蓋率數據: bash
測試覆蓋率報告:閉包
2.外置測試率報告 還能夠生成XML或HTML格式的報告。 生成包含覆蓋率數據的報告,須要啓用一下標記:框架
這些設置會在工程的衍生數據文件夾中生成.gcno和.gcda文件。.gcno包含重建基本代碼塊和塊對應源碼的詳細信息,.gcda包含代碼分支轉換的計數。異步
使用這些文件生成能夠導爲XML或HTML格式的報告:
使用Macposts或HomeBrew來安裝lcov軟件包 在Xcode的Build Phases中添加一個New Run Script Phase,從而生成報告。
lcov --directory "${OBJECT_FILE_DIR_normal}/${CURRENT_ARCH}" --capture --output-file "${PROJECT_DIR}\${PROJECT_NAME}.info" genhtml --output-directory "${PROJECT_DIR}/${PROJECT_NAME}-covergae" "${PROJECT_DIR}/${PROJECT_NAME}.name"
測試異步方法的步驟: (1)使用expectationWithDescription:方法來獲取XCTestExpectation實例。 (2)waitForExpectationsWithTimeout: handler:方法來等待操做完成。若是測試用例沒有完成,那麼將會調用回調處理的閉包塊。 (3)使用XCTestExpectation對象的fulfill方法來表示操做已經完成,等待結束。
-(void)testsignalForUserUpdates{ HPUserService *userSever = [[HPUserService alloc]init]; XCTestExpectation *expectation = [self expectationWithDescription:@"Test Fetch Type"];//1.建立XCTestExpectation 對象。能夠等待多個expectation。 [userSever catchType:@"user" WithId:@"1" block:^(NSDictionary *responseDict) {//2.執行要被測試的方法 NSString *key1Value = [responseDict objectForKey:@"key1"]; XCTAssertEqualObjects(@"uesrName", key1Value); //驗證數據,使用斷言 知足指望 這將致使後面的 -waitForExpectation 調用其completion handler而後返回。 [expectation fulfill]; }]; // 測試會等在這裏,運行着run loop,直到超時或者expectation被知足 [self waitForExpectationsWithTimeout:1 handler:^(NSError * _Nullable error) { NSLog(@"若是指望對象沒有知足,則進行清理操做"); }]; }
XCTestCase提供了方法measureBlock來測量一個代碼塊的性能。 一旦設置好基線,輸出結果將不只顯示平均值和標準差,還將顯示低於基線的最差結果。
添加一個系統來模擬依賴關係,帶有模擬依賴的測試用例的工做方式以下: (1)配置依賴項以便依照提早定義好的方式運行,返回特定的值,或根據特定的輸入改變至特定的狀態。 (2)執行測試用例。 (3)重置依賴項使一切正常工做。
依賴項在-[set up]方法中配置,在測試夾具的-[tear down]中重置。
詞彙
dummy/double(n.傀儡,adj.虛擬的) 用於描述模擬測試對象的通用詞彙,double共有4種類型
BDD 行爲驅動開發,是測試驅動開發的一種擴展。
mocking框架 容許建立dummy框架。
OCMock很是好的mocking框架:
-(void)testUserWithId_Completion{ id syncService = OCMClassMock([HPUserService class]);//模擬HPUserService類的一個對象 [OCMStub([syncService new]) andReturn:syncService];//stub操做,返回以前獲得的mock對象,在mock對象上調用某個方法的時候,這個方法必定返回一個anObject.(也就是說強制替換了某個方法的返回值爲anObject)。 //測試用例輸入 NSString *userId = @"user-id", *fname = @"fn-user-id", *lname = @"ln-user-id", *gender =@"gender-x"; NSDate *dob = [NSDate date]; NSDictionary *data = @{@"id":userId, @"fname":fname, @"lanme":lname, @"gender":gender, @"dateOfBirth":dob }; [OCMStub([syncService fetchType:OCMOCK_ANY WithId:OCMOCK_ANY completion:OCMOCK_ANY]) andDo:^(NSInvocation *invocation) {//andDo 在mock對象調用someMethod的時候,andDo後面的block會調用.block能夠從NSInvocation中獲得一些參數,而後使用這個NSInvocation對象來構造返回值等等. void (^callBack)(NSDictionary *); [invocation getArgument:&callBack atIndex:4]; callBack(data); }]; HPUserService *svc = [HPUserService new]; [svc fetchType:userId WithId:userId completion:^(NSDictionary *dic) {//配置完成開始測試 //進行驗證 XCTAssert(dic); XCTAssertEqualObjects(userId, dic[@"id"]); XCTAssertEqualObjects(fname, dic[@"fname"]); //...... }]; OCMVerify(syncService);//驗證方法以特定參數值被調用 }
參考文章:http://blog.csdn.net/jymn_chen/article/details/21562869, http://www.cnblogs.com/xilifeng/p/4690273.html
框架類型 | 名稱 | 保持器 | GitHub URL |
---|---|---|---|
mock對象 | OCMock | https://github.com/erikdoe/ocmock | |
OCMockito | https://github.com/jonreid/OCMockito | ||
匹配器 | Expecta | https://github.com/specta/expecta | |
OCHamcrest | https://github.com/hamcrest/OCHamcrest | ||
TDD/BDD框架 | Specta | https://github.com/specta/specta | |
Kiwi | https://github.com/kiwi-bdd/Kiw | ||
Cedar | https://github.com/pivotal/cedar | ||
Calabash | https://calaba.sh |
功能測試確保應用的功能與預期一致。 UITesting 參考文章:https://www.jianshu.com/p/31367c97c67d
持續集成能夠保持代碼清晰並確保構建即時更新。
性能測試: 爲測試的內容編寫特定的代碼,例如計算運行速度,使用一個簡化的計時器。 跟蹤運行速度的計算器代碼:
#import <Foundation/Foundation.h> @interface HPTimer : NSObject//公共API +(HPTimer *)startWithName:(NSString *)name; @property (nonatomic , readonly , assign) uint64_t timeNanos; @property (nonatomic , copy) NSString *name; -(uint64_t)stop; -(void)printTree; @end #import "HPTimer.h" #include <mach/mach_time.h> #import "CocoaLumberjack.h" #ifdef DEBUG static const DDLogLevel ddLogLevel = DDLogLevelDebug; #else static const DDLogLevel ddLogLevel = DDLogLevelError; #endif @interface HPTimer() @property (nonatomic , strong) HPTimer *parent; @property (nonatomic , strong) NSMutableArray *children; @property (nonatomic , assign) uint64_t startTime; @property (nonatomic , assign) uint64_t stopTime; @property (nonatomic , assign) BOOL stopped; @property (nonatomic , copy) NSString *threadName; @end @implementation HPTimer +(HPTimer *)startWithName:(NSString *)name{//建立新的定時器,用於計時 NSThread *thread = [NSThread new]; NSMutableDictionary *tls = thread.threadDictionary; HPTimer *top = [tls objectForKey:@"hp-timer-top"];//計時器上下文是線程的局部對象。在示例的實現中,一旦建立計時器上下文,計時器能夠在任意線程中止。這種實現能夠變爲讓計時器對限制線程調用stop方法,只在建立計時器的線程中調用 HPTimer *rv = [[HPTimer alloc]initWithParent:top name:name]; [tls setObject:rv forKey:@"hp-timer-top"]; rv.startTime = mach_absolute_time();//https://www.jianshu.com/p/82475b5a7e19 return rv; } -(instancetype)initWithParent:(HPTimer *)parent name:(NSString *)name{ if(self = [super init]){ self.parent = parent; self.name = name; self.stopped = NO; self.children = [NSMutableArray array]; self.threadName = [NSThread currentThread].name; if (parent){ [parent.children addObject:self]; } } return self; } -(uint64_t)stop{ self.stopTime = mach_absolute_time(); self.stopped = YES; //self.timeNanos = 獲取以納米爲單位的時間間隔self.startTime && self.stopTime NSThread *thread = [NSThread new]; NSMutableDictionary *tls = thread.threadDictionary; [tls setObject:self.parent forKey:@"hp-timer-top"];//從線程局部存儲中後去當前線程的計時器 return self.timeNanos; } -(void)printTree{ [self printTreeWithNode:self indent:@" "]; } -(void)printTreeWithNode:(HPTimer *)node indent:(NSString *)indent{//美化計時器樹輸出 if (node){ DDLogDebug(@"%@[%@][%@] -> %lld",indent,self.threadName,self.name,self.timeNanos); NSArray *childern = node.children; if (childern.count > 0){ indent = [indent stringByAppendingString:@" "]; for (NSUInteger i = 0;i<childern.count;i++){ [self printTreeWithNode:[childern objectAtIndex:i] indent:@" "]; } } } } @end #pragma mark BEGIN 調用 -(void)methodA{ HPTimer *timer = [HPTimer startWithName:@"method A"];//爲計時器賦予一個有意義的名字 [self methodB]; [timer stop];//運行後調用stop [timer printTree];//輸出運行耗時,包括任意嵌套的計時器 } -(void)methodB{ HPTimer *timer = [HPTimer startWithName:@"method B"];//在嵌套的方法調用中,建立其餘計時器 //do some thing [timer stop]; [timer printTree];//能夠輸出嵌套的調用樹 } #pragma EDN