我有一个从网络请求数据的方法,我想对它进行单元测试。但是当我在测试用例中设置一个断点时,断点就不会到达那里。
要测试的方法:
- (void)requestSuperDecisionDataWithCompletionHandler:(void (^)(NSArray *result))callBack {
static vector<vector<string>> arr;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//request data from network
IceNetwork::Init()->GetSuperDecision(arr);
if (arr.size() != kSuperDecisionDataCount) {
callBack(nil);
} else {
NSArray *convertedData = [self convertCArrayToNSArrayWithCArray:arr];
dispatch_async(dispatch_get_main_queue(), ^{
callBack(convertedData);
});
}
});
}
测试用例:
- (void)testThatRequestSuperDecisionDataShouldReturnZeroOr14Items
{
//super decision
[_requestManager requestSuperDecisionDataWithCompletionHandler:^(NSArray *result) {
//set a break point here
int dataCount = result.count;
XCTAssert(0 == dataCount || 16 == dataCount, @"should have 0 or 16 items");
}];
}
答案 0 :(得分:3)
在这种情况下,因为这是一个异步操作,所以测试在调用完成处理程序之前完成。考虑到这一点,有两种方法可以用来做到这一点,两者都涉及在允许测试完成之前等待完成处理程序的调用。
第一种方法使用Xcode 6 beta中提供的新API。
- (void)testThatRequestSuperDecisionDataShouldReturnZeroOr14Items {
// set an expectation for your test, in this case we expect the completion handler to be
// called within a reasonable amount of time
XCTestExpectation *expectation = [self expectationWithDescription:@"The completion handler should be called."];
// start whatever asyncronous task you want to do
[_requestManager requestSuperDecisionDataWithCompletionHandler:^(NSArray *result) {
// here we handle the actual meat of the tests
int dataCount = result.count;
XCTAssert(0 == dataCount || 16 == dataCount, @"should have 0 or 16 items");
// now we can tell the test that our expectation has been fulfilled, which will
// allow the test to complete
[expectation fulfill];
}];
// we want the test to wait for the expectations for some period of time, but we also
// want to establish some sort of timeout interval where the test will basically be
// terminated and the result will be a timeout failure, you can set the timeout to whatever
// interval you want for each case, and optionally provide a handler to clean up anything
[self waitForExpectationsWithTimeout:2 handler:nil];
}
如果您正在运行Xcode 5并且因此无法访问新API,则可以使用第二个选项,但基本上是相同的过程,只需稍微多一点。
- (void)testThatRequestSuperDecisionDataShouldReturnZeroOr14Items {
// create a BOOL flag that will keep track of whether or not we're still
// waiting for the completion block to be called
__block BOOL waitingForBlock = YES;
// start whatever asyncronous task you want to do
[_requestManager requestSuperDecisionDataWithCompletionHandler:^(NSArray *result) {
// here we handle the actual meat of the tests
int dataCount = result.count;
XCTAssert(0 == dataCount || 16 == dataCount, @"should have 0 or 16 items");
// now we can update the waitingForBlock variable to NO as we are no
// longer waiting for it to complete
waitingForBlock = NO;
}];
// kill the test after some specified delay if we haven't completed yet - just in case something
// happens with the test where the handler will never be called, at least the test will complete
// and we will know we timed-out.
NSTimeInterval seconds = 3;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
XCTFail(@"'testThatRequestSuperDecisionDataShouldReturnZeroOr14Items' failed due to timeout.");
waitingForBlock = NO;
});
// loop while we are waiting for the completion handler to finish
while (waitingForBlock) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}