问题提出:
XCTest是xcode内置的单元测试框架,方便我们对那些不依赖UI的业务模块做单元测试,但是对于一些网络模块的异步调用,需要将测试模块的生命周期延长,等回调成功才释放。
那么我们如体利用XCTest做异步单元测试呢?比如:如何对http网络接口做单元测试?
解决方案
由于XCTest是中只一个主线程,且并没有维护一个NSRunLoop,如果需要异步调用做单元测试,需要自己管理NSRunLoop
更好的解决
GitHub大神已经很优雅的解决了这个问题
//
// XCTest+Async.h
//
// Created by Saül Baró on 10/29/13.
// Copyright (c) 2013 Wide Eyes Solutions SL. All rights reserved.
//
#import <XCTest/XCTest.h>
#define ASYNC_TEST_START __block BOOL hasCalledBack = NO;
#define ASYNC_TEST_DONE hasCalledBack = YES;
#define ASYNC_TEST_END NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:10]; \
while (hasCalledBack == NO && [loopUntil timeIntervalSinceNow] > 0) { \
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:loopUntil]; \
} \
if (!hasCalledBack) { XCTFail(@"Timeout"); }
#define ASYNC_TEST_END_LONG_TIMEOUT \
NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:120]; \
while (hasCalledBack == NO && [loopUntil timeIntervalSinceNow] > 0) { \
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:loopUntil]; \
} \
if (!hasCalledBack) { XCTFail(@"Timeout"); }
@interface XCTest (Async)
@end
如何使用
将 XTest+Async.h 这个分类头文件引入测试例类, 看下面的实例
ASYNC_TEST_START 异步任务开始
ASYNC_TEST_DONE 异步任务完成
ASYNC_TEST_END 异步任务超时,10秒
ASYNC_TEST_END_LONG_TIMEOUT 设置异步任务超时时间,120秒
// 引入头文件
import "XCTest+Async.h"
- (void)testExample
{
ASYNC_TEST_START;
dispatch_queue_t kBgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(kBgQueue, ^{
NSData* repositoryData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://api.github.com/repos/mobilejazz/XCTest-Async"]];
NSError* error;
if (repositoryData) {
NSDictionary* repositoryInfo = [NSJSONSerialization JSONObjectWithData:repositoryData
options:kNilOptions
error:&error];
if (error) {
XCTFail(@"The data was not a dictionary");
}
else {
XCTAssertNotNil(repositoryInfo, @"XCTest-Async repo:");
NSLog(@"Repos %@", repositoryInfo);
}
}
else {
XCTFail(@"The operation couldn't be completed");
}
ASYNC_TEST_DONE;
});
ASYNC_TEST_END;
}