Как протестировать асинхронный метод в блоке с помощью OCMock

Я не могу понять, как проверить этот метод:

- (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?

спасибо


person jimijon    schedule 06.09.2013    source источник


Ответы (2)


Один из способов протестировать вызовы асинхронных методов — дождаться их завершения:

__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];

Этому методу я научился, просматривая , в котором также есть несколько приятных трюков с использованием семафоров.

person Ben Flynn    schedule 07.09.2013

Я написал библиотеку, реализующую «Обещание». Оказалось, что эта концепция полезна не только для решения сложных асинхронных задач, но и для тестирования:

Предположим, у вас есть какой-то асинхронный метод и вы хотите проверить, будет ли вызван обработчик завершения и вернет ли он ожидаемый результат. В качестве бонуса вы также хотите установить тайм-аут, в течение которого тестер ожидает обработчик завершения. Если он истекает, тест должен провалиться.

Общий блок обработчика завершения:

typedef void (^completion_block_t)(id result);

Ваш тест, асинхронный метод, который может основываться на цикле выполнения:

- (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:s может быть запланирована в цикле выполнения, который выполняется в соответствующем потоке, например основной поток.

Обработчик завершения может также выполняться в том же цикле выполнения, например на основной ветке.

    // 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
person CouchDeveloper    schedule 07.09.2013
comment
Это выглядит интересно. У вас есть на гитхабе? - person Ben Flynn; 08.09.2013
comment
@BenFlynn Да, это на GitHub с лицензией Apache версии 2: RXPromise. - person CouchDeveloper; 08.09.2013