我编写了一个实现“承诺”的库。事实证明,这个概念不仅对解决复杂的异步问题有用,而且对测试也有用:
假设您有一些异步方法,并且想要检查是否会调用完成处理程序,以及它是否返回预期结果。作为奖励,您还需要设置测试人员等待完成处理程序的超时。如果它过期,则测试应该失败。
通用完成处理程序块:
typedef void (^completion_block_t)(id result);
你的 testie,一个可能基于运行循环的异步方法:
- (void) asyncFooWithCompletion:(completion_block_t)completionHandler;
您的测试可能如下所示:
- (void) testAsyncFooWithCompletion
{
// Your test - executing on the main thread.
RXPromise* handlerPromise = [RXPromise new];
[foo asyncFooWithCompletion:^(id result){
// possibly perform assertions
...
if (result is expected) {
// expected in this test scenario
// resolve promise with a value indicating success:
[handlerPromise fulfillWithValue:@"OK"];
}
else {
// unexpected in this test scenario
// resolve promise with an error:
[handlerPromise rejectWithReason:@"Unexpected result"];
}
}];
注意:asyncFooWithCompletion:
工作负载可以安排在一个运行循环上,该循环在相应的线程上执行——例如主线程。
完成处理程序也可以在相同的运行循环上执行,例如在主线程上。
// Set a timeout. If the timeout expires before the handler get called,
// the promise will be resolved with a "timeout error":
[handlerPromise setTimeout:5.0];
// Register handlers, which get called when _handlerPromise_ will be resolved.
// We did perform a all assertions in the completion handler. Thus here,
// just catch unexpected failures - including a timeout:
[handlerPromise.thenOn(dispatch_get_main_queue(), nil,
^id(NSError* error) {
// We are on the main thread
ADD_FAILURE() << [[error description] UTF8String];
return error;
})
runLoopWait]; // wait on the current run loop.
// if we reach here, assertions have been executed (on the main thread)
// and all handlers have been returned.
} // end test