2012-09-17 7 views
13

Я читал другие сообщения, которые придумывают решения этого вопроса. Тем не менее, их решения требуют, чтобы хеш-код был добавлен в мое приложение, чтобы проверить его. Для меня чистый код более важен, чем модульный тест.Цель C - Блокировать модуль dispatch_async?

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

Я НЕ хочу, чтобы передать завершение к блоку только из модульного тестирования

- (viod)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Test passes on this 
    [self.serviceClient fetchDataForUserId:self.userId]; 


    // Test fails on this because it's asynchronous 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.serviceClient fetchDataForUserId:self.userId]; 
    }); 
} 

- (void)testShouldFetchUserDataUsingCorrectId 
{ 
    static NSString *userId = @"sdfsdfsdfsdf"; 
    self.viewController.userId = userId; 
    self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]]; 

    [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId]; 
    [self.viewController view]; 
    [(OCMockObject *)self.viewController.serviceClient verify]; 
} 

ответ

37

запуск главного кратко цикла, чтобы это вызвать асинхронный блок:

- (void)testShouldFetchUserDataUsingCorrectId { 
    static NSString *userId = @"sdfsdfsdfsdf"; 
    self.viewController.userId = userId; 
    self.viewController.serviceClient = [[OCMockObject niceMockForClass:[ServiceClient class]]; 

    [[(OCMockObject *)self.viewController.serviceClient expect] fetchDataForUserId:userId]; 
    [self.viewController view]; 
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; 
    [(OCMockObject *)self.viewController.serviceClient verify]; 
} 

Я предполагаю, что это может не на сильно загруженную систему, или если у вас есть куча других вещей (таймеры или других блоки), идущий по основной теме. Если это так, вам нужно запустить цикл выполнения дольше (что замедляет ваш тестовый пример) или выполнить его повторно до тех пор, пока ожидания макета не будут выполнены или не будет достигнут тайм-аут (что требует добавления метода к макету объекта вопрос о том, были ли выполнены его ожидания).

+0

Используя этот код, блок не вызывается вообще, даже после завершения теста. – aryaxt

+0

Я пересмотрел свой ответ. Я более тщательно тестировал этот подход. –

+0

Спасибо. Этот метод не кажется надежным, но я не нашел лучшего решения, поэтому я продолжу его использование и надеюсь, что он не нарушит мои тесты. – aryaxt

10

Оберните выполнения в dispatch_group, а затем ждать группы, чтобы закончить выполнение всех запускаемых блоков с помощью dispatch_group_wait().

+0

Очень интересно. Никогда не слышал о диспетчерской группе раньше. Я не могу использовать NSOperationQueues снова. Единственной проблемой, с которой я столкнулся с GCD, было отсутствие этой функции. – aryaxt

+0

@aryaxt Yup, диспетчерские группы очень полезны, но редко упоминаются где-нибудь (даже официальные документы Apple не очень подробные о них) – JustSid

+0

Это очень полезная техника. Он должен получить больше взлетов. – e2l3n

0

Сделайте обертку dispatch_async с аналогичной сигнатурой метода, которая в свою очередь вызывает реальный dispatch_async. Зависимость вставляет оболочку в ваш производственный класс и использует это.

Затем сделайте фальшивую обертку, в которой записаны блокированные блоки и есть дополнительный метод для синхронного запуска всех заблокированных блоков. Возможно, выполнить рекурсивное «блокирование», если выполняемые блоки поочередно ставят в очередь больше блоков.

В ваших модульных тестах вводите макетную обертку в тестируемую систему. Затем вы можете сделать все синхронно, хотя SUT считает, что он выполняет асинхронную работу.

dispatch_group также звучит как хорошее решение, но для того, чтобы выполнить команду ping, отправьте команду отправки в конец блоков, в которые она попадает.