3

我似乎无法弄清楚如何测试这种方法:

- (void)writer:(id)writer didFailWithError:(NSError *)error;
{    
 [self.alertView dismissWithClickedButtonIndex:0 animated:YES];

  void (^alertViewBlock)(int) = ^(int buttonIndex)
  {
    if (buttonIndex == 1)
    {
        [self performSelectorOnMainThread:@selector(savePostponeReasonsAsynchronously) withObject:nil waitUntilDone:NO];
    }
    else
    {
        NSLog(@"dismissed");

        self.savePostponeReasonsQueue = nil;
    }
  };

 [self showPostponeReasonFailedAlert:alertViewBlock];
}

具体来说,我如何测试选择器 savePostponeReasonsAsynchronously 是否被调用?

谢谢

4

2 回答 2

4

测试异步方法调用的一种方法是等待它们完成:

__block BOOL isRunning = YES;
[[[myPartialMock expect] andDo:^(NSInvocation *invocation){ isRunning = NO; }] savePostponeReasonsAsynchronously];
myPartialMock writer:nil didFailWithError:nil; 

NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:10];
do {
  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                           beforeDate:timeout];
} while (isRunning);

STAssertFalse(isRunning, @"Test timed out.");
[myPartialMock verify];

这是我通过查看 Rob Napier 的RNCryptor 测试代码学到的一种技术,它也有一些使用信号量的好技巧。

于 2013-09-07T19:17:57.870 回答
0

我编写了一个实现“承诺”的库。事实证明,这个概念不仅对解决复杂的异步问题有用,而且对测试也有用:

假设您有一些异步方法,并且想要检查是否会调用完成处理程序,以及它是否返回预期结果。作为奖励,您还需要设置测试人员等待完成处理程序的超时。如果它过期,则测试应该失败。

通用完成处理程序块:

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
于 2013-09-07T23:08:53.547 回答