我在iOS中单元测试异步调用时遇到问题.(虽然它在视图控制器中工作正常.)
以前有人遇到过这个问题吗?我尝试过使用等待功能,但我仍然遇到同样的问题.
请提供一个很好的方法来举例说明.
Jac*_*kin 28
你需要旋转runloop直到你的回调被调用.但要确保它在主队列上被调用.
试试这个:
__block BOOL done = NO;
doSomethingAsynchronouslyWithBlock(^{
done = YES;
});
while(!done) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Run Code Online (Sandbox Code Playgroud)
您也可以使用信号量(下面的示例),但我更喜欢旋转runloop以允许处理分派到主队列的异步块.
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
doSomethingAsynchronouslyWithBlock(^{
//...
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
Run Code Online (Sandbox Code Playgroud)
sky*_*der 13
TL; DR手册:
看着 XCTextCase+AsynchronousTesting.h
有XCTestExpectation一个只有一个公共方法的特殊类:- (void)fulfill;
您应该初始化此类的实例并在成功案例中调用fulfill方法.否则,您在该方法中指定的超时后测试将失败:
- (void)waitForExpectationsWithTimeout:(NSTimeInterval)timeout handler:(XCWaitCompletionHandler)handlerOrNil;
Run Code Online (Sandbox Code Playgroud)
例:
- (void)testAsyncMethod
{
//Expectation
XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Async Method Works Correctly!"];
[MyClass asyncMethodWithCompletionBlock:^(NSError *error) {
if(error)
NSLog(@"error is: %@", error);
else
[expectation fulfill];
}];
//Wait 1 second for fulfill method called, otherwise fail:
[self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
if(error)
{
XCTFail(@"Expectation Failed with error: %@", error);
}
}];
}
Run Code Online (Sandbox Code Playgroud)
我认为这篇文章中的许多建议解决方案存在的问题是,如果异步操作没有完成,则永远不会设置"完成"标志,并且测试将永久挂起.
我在很多测试中都成功地使用了这种方法.
- (void)testSomething {
__block BOOL done = NO;
[obj asyncMethodUnderTestWithCompletionBlock:^{
done = YES;
}];
XCTAssertTrue([self waitFor:&done timeout:2],
@"Timed out waiting for response asynch method completion");
}
- (BOOL)waitFor:(BOOL *)flag timeout:(NSTimeInterval)timeoutSecs {
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
if ([timeoutDate timeIntervalSinceNow] < 0.0) {
break;
}
}
while (!*flag);
return *flag;
}
Run Code Online (Sandbox Code Playgroud)