一、概述
在Xcode中新建项目的时候会默认勾选单元测试,勾选后每个XCode新建的iOS的项目中都有一个叫做”项目名Tests”的分组,这个分组里就是XCTestCase的子类,XCTest中的测试类都是继承自XCTestCase。当我们为项目增加了新的功能时,可以使用单元测试针对该模块进行测试。
二、单元测试的使用
1、常规测试
首先新建一个名为“MyDemo”的项目,我们会看到会自动生成如下的文件:
MyDemoTests中代码为:
#import <XCTest/XCTest.h>
@interface MyDemoTests : XCTestCase
@end
@implementation MyDemoTests
- (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.
}];
}
@end
上面最重要的两个方法为setUp和tearDown,setUp方法在XCTestCase的测试方法调用之前调用。当测试全部结束之后调用tearDown方法。上面的另外两个方法是系统自动创建的功能测试用例的示例。我们可以自己创建测试方法,不过测试方法必须testXXX的格式,且不能有参数,不然不会识别为测试方法。
setUp方法可以在测试之前创建在test case方法中需要用到的一些对象等。tearDown方法则在全部的test case执行结束之后清理测试现场,释放资源删除不用的对象等。
例如,我们去除系统系统创建的两个测试用例的示例,我们自己创建一个方法:
#import <XCTest/XCTest.h>
@interface MyDemoTests : XCTestCase
@end
@implementation MyDemoTests
- (void)setUp {
[super setUp];
NSLog(@"setUp-----------------");
}
- (void)tearDown {
[super tearDown];
NSLog(@"tearDown-----------------");
}
- (void)testMyFun{
NSLog(@"testMyFun-----------------");
}
@end
按快捷键Command + U进行单元测试,打印结果(去除了其他暂不关注的打印):
2017-03-06 15:35:35.336 MyDemo[48088:5078800] setUp-----------------
2017-03-06 15:35:35.336 MyDemo[48088:5078800] testMyFun-----------------
2017-03-06 15:35:35.337 MyDemo[48088:5078800] tearDown-----------------
接下来我们新建一个类MyClass,在MyClass中声明和实现一个getNum的方法,方法实现如下:
-(NSInteger)getNum{
return 5;
}
然后在我们MyDemoTests的testMyFun写相关单元测试代码(代码中用到了断言,断言的使用后面再讲):
#import <XCTest/XCTest.h>
#import "MyClass.h"
@interface MyDemoTests : XCTestCase
@end
@implementation MyDemoTests
- (void)setUp {
[super setUp];
NSLog(@"setUp-----------------");
}
- (void)tearDown {
[super tearDown];
NSLog(@"tearDown-----------------");
}
- (void)testMyFun{
NSLog(@"testMyFun-----------------");
MyClass *myClass = [[MyClass alloc]init];
NSInteger num = [myClass getNum];
XCTAssert(num < 10,@"num should less than 10");
}
@end
上面加了断言,只有当num<10的使用才能通过测试,由于此时num=5,所以可以顺利通过测试。
按快捷键Command + U进行单元测试,结果如下:
如果我们将getNum的返回结果改为15,则不会通过测试:
如果测试方法比较多的时候也可以直接点击方法后运行的图标单独测试某个方法,Command + U是全部测试:
2、性能测试
刚开始的时候系统为我们创建的一个测试用例方法里有这么个方法:
- (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)testPerformanceExample {
NSLog(@"testPerformanceExample-----------------");
[self measureBlock:^{
MyClass *myClass = [[MyClass alloc]init];
[myClass getNum];
}];
}
按快捷键Command + U进行单元测试,结果如下:
2017-03-06 16:42:01.403 MyDemo[51107:5178923] setUp-----------------
2017-03-06 16:42:01.404 MyDemo[51107:5178923] testPerformanceExample-----------------
/Users/lifengfeng/Desktop/Project/iOSProject/MyDemo/MyDemoTests/MyDemoTests.m:31: Test Case '-[MyDemoTests testPerformanceExample]' measured [Time, seconds] average: 0.422, relative standard deviation: 164.533%, values: [0.000053, 2.073384, 0.000010, 1.073334, 0.000013, 1.074108, 0.000016, 0.000005, 0.000004, 0.000003], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
2017-03-06 16:42:06.080 MyDemo[51107:5178923] tearDown-----------------
3、常用的测试断言
XCTFail(format) 生成一个失败的测试;
XCTFail(@"Fail");
XCTAssertNil(a1, format…) 为空判断, a1 为空时通过,反之不通过;
XCTAssertNil(@”not nil string”, @”string must be nil”);
XCTAssertNotNil(a1, format…) 不为空判断,a1不为空时通过,反之不通过;
XCTAssertNotNil(@”not nil string”, @”string can not be nil”);
XCTAssert(expression, format…) 当expression求值为TRUE时通过;
XCTAssert((2 > 2), @”expression must be true”);
XCTAssertTrue(expression, format…) 当expression求值为TRUE时通过;
XCTAssertTrue(1, @”Can not be zero”);
XCTAssertFalse(expression, format…) 当expression求值为False时通过;
XCTAssertFalse((2 < 2), @”expression must be false”);
XCTAssertEqualObjects(a1, a2, format…) 判断相等, [a1 isEqual:a2] 值为TRUE时通过,其中一个不为空时,不通过;
XCTAssertEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return YES”);
XCTAssertNotEqualObjects(a1, a2, format…) 判断不等, [a1 isEqual:a2] 值为False时通过,
XCTAssertNotEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return NO”);
XCTAssertEqual(a1, a2, format…) 判断相等(当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以);
XCTAssertNotEqual(a1, a2, format…) 判断不等(当a1和a2是 C语言标量、结构体或联合体时使用);
XCTAssertEqualWithAccuracy(a1, a2, accuracy, format…) 判断相等,(double或float类型)提供一个误差范围,当在误差范围(+/- accuracy )以内相等时通过测试;
XCTAssertEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return YES”);
XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format…) 判断不等,(double或float类型)提供一个误差范围,当在误差范围以内不等时通过测试;
XCTAssertNotEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return NO”);
XCTAssertThrows(expression, format…) 异常测试,当expression发生异常时通过;反之不通过;
XCTAssertThrowsSpecific(expression, specificException, format…) 异常测试,当expression发生 specificException 异常时通过;反之发生其他异常或不发生异常均不通过;
XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format…) 异常测试,当expression发生具体异常、具体异常名称的异常时通过测试,反之不通过;
XCTAssertNoThrow(expression, format…) 异常测试,当expression没有发生异常时通过测试;
XCTAssertNoThrowSpecific(expression, specificException, format…) 异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过;
XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format…) 异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过;