测试目标和部署目标中异步代码的不同行为

时间:2013-09-21 20:30:34

标签: objective-c xcode ocunit

在尝试将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.
}

可能是什么问题?

1 个答案:

答案 0 :(得分:0)

你应该详细说明[SomeClass performActionWithAsyncResponse]如何完成它的工作。

假设在主队列的块中调用了completionWithResult,这将无效,因为线程在测试方法完成后结束。生产中并非如此,因为应用程序一直在运行。

通常我使用这样的代码来等待在测试中回调主队列的异步调用。

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

您还可以使用一个条件来停止while循环,该条件指示异步工作是否已完成,例如使用测试的属性。

有关异步测试模式的更多信息,请参阅此帖子: Pattern for unit testing async queue that calls main queue on completion