关于XCTest
命名
所有测试的方法都需要以test为前缀进行命名,比如:
/**
* @brief 测试发送带参数事件成功
*
* @since 0.0.1
*/
- (void)testTrackEventWithAttr{
//测试代码
}
一般我们命名的时候会使用这个方法要测试的内容,比如testHTTPRequest。
另外,对于每一个业务类,我们都会有一个对应的测试类,比如:GMNetService对应GMNetServiceTest,如果类的内容太多,我们也可以通过Category进行分类。
如果某个方法我们暂时不想跑测试了,我们可以加一个Disable前缀,比如:
- (void)DISABLED_testTrackEventWithAttr
setUp和tearDown
在每个单元测试方法执行之前,XCTest会先执行setUp方法,所以可以把一些测试代码需要用的初始化代码和全局变量写在这个方法里,比如:
- (void)setUp {
[super setUp];
_client = [Phobos clientWithAppName:MockAppName channelId:MockChannelId];
[Phobos setSharedClient:_client];
_cache = [WMCacheService sharedInstance];
}
另外,在每个单元测试方法执行完毕后,XCTest会执行tearDown方法,所以可以把需要测试完成后销毁的内容写在这个里,以便保证下面的测试不受本次测试影响,比如:
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
[_cache removeObjectAtDiskWithkey:PhobosCacheKey];
}
三个步骤(Given/When/Then)
编写单元测试代码可以分为Given-When-Then三个步骤
Given指的是构建整个测试上下文,建立好相关模型
When代表我们需要测试的业务逻辑,一般情况只是调用一个方法
Then检查一下测试结果是否符合我们的预期
比如下面的代码:
/**
* @brief 测试立即发送带参数事件成功
*
* @since 0.0.1
*/
- (void)testTrackEventWithAttrAndSendNow{
// Given
NSDictionary *attr = @{@"attr":@"track_attr"};
// When
[_client track:MockEventId attributes:attr sendNow:YES];
// Then
NSArray *array = [_cache fetchObjectAtDiskWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array should be empty");
}
性能测试
Xcode6之后,XCTest提供性能测试,主要是针对某个代码块执行的时长,可以自己设定Baseline来作为测试是否通过的基准,用法很简单:
/**
* @brief 测试50条数据压缩速度
*
* @description 经过测试50条数据压缩大约1毫秒左右,几乎不耗时
*
* @since 0.0.7
*/
- (void)testDataCompressPerformance {
[self measureBlock:^{
[self encodeAndCompressArray:_mockArray];
}];
}
测试异步任务
当我们测试网络请求等异步任务时,如果按上面的普通写法来写的话,测试的Case在主线程执行完毕后就会结束,并不会执行异步线程的回调,比如:
- (void)testSendDataToMars{
NSData *mockData = [self encodeAndCompressArray:_mockArray];
[PhobosUtil sendData:mockData success:^(NSInteger code) {
XCTAssertEqual(code, 200);
}];
}
还好,XCTest框架提供了一个XCTestExpectation来处理异步任务的测试,用法如下:
/**
* @brief 发送数据测试
*
* @since 0.0.7
*/
- (void)testSendDataToMars{
XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method Works!"];
NSData *mockData = [self encodeAndCompressArray:_mockArray];
[PhobosUtil sendData:mockData success:^(NSInteger code) {
[expectation fulfill];
XCTAssertEqual(code, 200);
}];
//如果超时,则认为发送失败
[self waitForExpectationsWithTimeout:3 handler:^(NSError *error) {
if(error)
{
XCTFail(@"Expectation Failed with error: %@", error);
}
}];
}