无法达到XCTestCase中的断点

时间:2014-08-14 07:59:17

标签: ios xctest

我有一个从网络请求数据的方法,我想对它进行单元测试。但是当我在测试用例中设置一个断点时,断点就不会到达那里。

要测试的方法:

- (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");
    }];
}

1 个答案:

答案 0 :(得分:3)

在这种情况下,因为这是一个异步操作,所以测试在调用完成处理程序之前完成。考虑到这一点,有两种方法可以用来做到这一点,两者都涉及在允许测试完成之前等待完成处理程序的调用。

第一种方法使用Xcode 6 beta中提供的新API。

方法#1 - 新的XCTestExpectation 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,则可以使用第二个选项,但基本上是相同的过程,只需稍微多一点。

方法#2 - 自己动手执行异步测试

- (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]];
    }
}