Подтвердить что ты не робот

Объект C - блок тестирования dispatch_async block?

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

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

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

- (viod)viewDidLoad
{
   [super viewDidLoad];

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


   // Test fails on this because it 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];
}
4b9b3361

Ответ 1

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

- (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];
}

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

Ответ 2

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

Ответ 3

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

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

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

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