iOS单元测试:等待期望的时间间隔

Lef*_*nia 12 unit-testing ios xcode6

我正在尝试更新我的异步单元测试以使用新XCTestExpectation接口而不是手动旋转运行循环.

我的单元测试之前使用的功能waitForBlock,finishBlock以及waitForTimeInterval:这很简单,称为一个方便的方法finishBlock在指定的时间之后.我正在尝试更新此设置以使用期望值.

使用waitForBlock+ finishBlock语义的测试在被替换为waitForExpectationsWithTime:handler:和之后都正常工作fulfill,但我的替换解决方案waitForTimeInterval:似乎不起作用.

- (void)waitForTimeInterval:(NSTimeInterval)delay
{
    XCTestExpectation *expectation = [self expectationWithDescription:@"wait"];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [expectation fulfill];
    });

    [self waitForExpectationsWithTimeout:delay + 1 handler:nil];
}
Run Code Online (Sandbox Code Playgroud)

编辑:

似乎代码实际上确实有效...所以这可能只是Xcode 6今天下午与我联系.


我觉得它应该是相当简单的:创建一个期望,设置一个满足的异步块,然后等待.但是,dispatch_after永远不会调用该块.

我的预感是waitForExpectationsWithTimeout:handler:阻塞它的当前线程,这是主队列,因此运行循环永远不会到达其异步块.这似乎是合理的,但我在提出实现此功能的不同方法时遇到了麻烦.

我正在寻找1)关于XCTestExpectation这可能揭示解决方法的其他信息,或2)实现此功能的不同想法.

Zme*_*mey 9

dispatch_async(dispatch_get_main_queue(), ...)似乎在Xcode 7 UI Tests中不起作用,永远不会调用完成处理程序.performSelector在Swift中不再可用,但还有另外两种解决方法:

  1. 使用计时器

    var waitExpectation: XCTestExpectation?
    
    func wait(duration: NSTimeInterval) {
        waitExpectation = expectationWithDescription("wait")
        NSTimer.scheduledTimerWithTimeInterval(duration, target: self,
            selector: Selector("onTimer"), userInfo: nil, repeats: false)
        waitForExpectationsWithTimeout(duration + 3, handler: nil)
    }
    
    func onTimer() {
        waitExpectation?.fulfill()
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在全局队列上运行块(它可以工作,但可能不安全,因为它没有记录XCTestExpectation是线程安全的任何地方).

    func wait(duration: NSTimeInterval) {
        let expectation = expectationWithDescription("wait")
        let dispatchTime = dispatch_time(DISPATCH_TIME_NOW,
            Int64(duration * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime,
            dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            expectation.fulfill()
        }
        waitForExpectationsWithTimeout(duration + 3, handler: nil)
    }
    
    Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 6

我已经在许多项目中使用XCTestExpectation来处理各种异步Web和GCD内容...... AFAIK,类似以下内容似乎是最常见的用法:

- (void)testExample {
    // create the expectation with a nice descriptive message
    XCTestExpectation *expectation = [self expectationWithDescription:@"The request should successfully complete within the specific timeframe."];

    // do something asyncronously
    [someObject doAsyncWithCompletionHandler:^(NSInteger yourReturnValue) {
        // now that the async task it done, test whatever states/values you expect to be after this is
        // completed
        NSInteger expectedValue = 42;
        XCTAssert(yourReturnValue == expectedValue, @"The returned value doesn't match the expected value.");

        // fulfill the expectation so the tests can complete
        [expectation fulfill];
    }];

    // wait for the expectations to be called and timeout after some
    // predefined max time limit, failing the test automatically
    NSTimeInterval somePredefinedTimeout = 3;
    [self waitForExpectationsWithTimeout:somePredefinedTimeout handler:nil];
}
Run Code Online (Sandbox Code Playgroud)


Lef*_*nia 5

显然使用performSelector:withObject:afterDelay:预期的作品,虽然我仍然不确定为什么.如果有人知道为什么GCD dispatch_after不起作用,请提供额外的答案,我会接受.目前,此设置似乎按预期工作:

- (void)waitForTimeInterval:(NSTimeInterval)delay
{
    XCTestExpectation *expectation = [self expectationWithDescription:@"wait"];
    [self performSelector:@selector(fulfillExpectation:) withObject:expectation afterDelay:delay];

    [self waitForExpectationsWithTimeout:delay + 1 handler:nil];
}

- (void)fulfillExpectation:(XCTestExpectation *)expectation
{
    [expectation fulfill];
}
Run Code Online (Sandbox Code Playgroud)