Различное поведение асинхронного кода в целевом объекте тестирования и целевом объекте развертывания

Пытаясь применить TDD к асинхронному коду, я обнаружил, что тот же самый код, который работал в целевом объекте развертывания, не работал в тестовом целевом объекте. Один из примеров этой проблемы, которую я нашел с помощью CLLocationManager:

- (void)testReceivingLocation
{
    locationManager = [[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    locationManager.delegate = self;
    locationManager.pausesLocationUpdatesAutomatically = NO;
    if ([CLLocationManager locationServicesEnabled])
    {
        [locationManager startUpdatingLocation];
    }
    startLocation = nil;

    NSDate *until = [NSDate dateWithTimeIntervalSinceNow:10];
    while ([until timeIntervalSinceNow] > 0)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:until];
    }
    XCTAssert(alreadyReceivedLocation, @"Location wasn't received.");
}

-(void)locationManager:(CLLocationManager *)manager
   didUpdateToLocation:(CLLocation *)newLocation
          fromLocation:(CLLocation *)oldLocation
{
    alreadyReceivedLocation = true;
    // Never actually get there.
}

В чем может быть проблема?


person Sergey    schedule 21.09.2013    source источник


Ответы (1)


Вам следует подробнее остановиться на том, как [SomeClass PerformActionWithAsyncResponse] выполняет свою работу.

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

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

NSDate *until = [NSDate dateWithTimeIntervalSinceNow:30];
while ([loopUntil timeIntervalSinceNow] > 0) 
{
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:until];
}

Вы также можете остановить цикл while с условием, указывающим, выполняется ли асинхронная работа, например, используя свойство теста.

См. этот пост для получения дополнительной информации о шаблонах асинхронного тестирования: ">Шаблон для модульного тестирования асинхронной очереди, которая вызывает основную очередь по завершении

person sofacoder    schedule 22.09.2013
comment
Спасибо за указатель! Я обновил вопрос, указав конкретный метод, который использую, и попытался использовать ваш код вместо sleep(). К сожалению, ничего не изменилось... - person Sergey; 22.09.2013
comment
Ах, CLLoactionManager Бьюсь об заклад, в симуляторе просто нет обновлений местоположения. Можете ли вы попробовать запустить тест на устройстве с GPS-фиксом? CLLocationManager ведет себя в симуляторе немного иначе. - person sofacoder; 22.09.2013