添加测试目标: 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