问题 在为目标C进行单元测试时,如何测试块?


我有一个函数(内部使用ASIHTTPRequest),它调用一个结果块:

[Http get:@"http://api.geonames.org/postalCodeLookupJSON"
   params:params cacheMins:0 complete:^(NSDictionary *response, BOOL success) {
       STAssertTrue(success, @"JSON retrieved OK");
       STFail(@"blah");
}];

我想测试上面的内容,但似乎测试没有被调用。

我怎样才能确保测试等到块被调用?

-编辑-

当然我不建议在gui线程的主应用程序中执行此操作,在这种特殊情况下,它仅用于单元测试。


11196
2018-04-13 02:53


起源



答案:


找到了解决方案:

等待代码完成执行

例如:

__block int done=0;
[Http get:@"http://api.geonames.org/postalCodeLookupJSON"
   params:params cacheMins:0 complete:^(NSDictionary *response, BOOL success) {
       STAssertTrue(success, @"JSON retrieved OK");
       NSArray *postalcodes = [response objectForKey:@"postalcodes"];
       NSDictionary *first = [postalcodes objectAtIndex:0];
       NSString *adminName1 = [first objectForKey:@"adminName1"];
       STAssertTrue([adminName1 isEqualToString:@"New South Wales"], @"NSW");
       done=1;
}];

// https://stackoverflow.com/questions/3615939/wait-for-code-to-finish-execution
while (!done) {
    // This executes another run loop.
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    // Sleep 1/100th sec
    usleep(10000);
}

7
2018-04-13 04:07



那个睡眠(10)会不会停止当前线程(不是运行块的线程)?如果它是您的主线程,则从那时启动块,睡眠将阻止GUI。 - Damien
哎呀我会编辑它。应该是'usleep'。而你是对的,它将停止主线程并阻止gui。但是 - 这只是一个单元测试。 - Chris


答案:


找到了解决方案:

等待代码完成执行

例如:

__block int done=0;
[Http get:@"http://api.geonames.org/postalCodeLookupJSON"
   params:params cacheMins:0 complete:^(NSDictionary *response, BOOL success) {
       STAssertTrue(success, @"JSON retrieved OK");
       NSArray *postalcodes = [response objectForKey:@"postalcodes"];
       NSDictionary *first = [postalcodes objectAtIndex:0];
       NSString *adminName1 = [first objectForKey:@"adminName1"];
       STAssertTrue([adminName1 isEqualToString:@"New South Wales"], @"NSW");
       done=1;
}];

// https://stackoverflow.com/questions/3615939/wait-for-code-to-finish-execution
while (!done) {
    // This executes another run loop.
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    // Sleep 1/100th sec
    usleep(10000);
}

7
2018-04-13 04:07



那个睡眠(10)会不会停止当前线程(不是运行块的线程)?如果它是您的主线程,则从那时启动块,睡眠将阻止GUI。 - Damien
哎呀我会编辑它。应该是'usleep'。而你是对的,它将停止主线程并阻止gui。但是 - 这只是一个单元测试。 - Chris


不确定我在哪里发现这个,但有一种更好的方法不使用睡眠:

while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !placeMarkUpdated){};

这是在上下文中,测试反向地理编码请求:

__block BOOL placeMarkUpdated = NO;

[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
    if (placeMarkUpdated == NO) {
        placeMarkUpdated = YES;
        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        address = [Address addressFromPlacemark:placemark];
    }
}];

while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !placeMarkUpdated){};

睡觉吮吸导致他们减慢构建速度(我知道5s听起来并不坏,但考虑一下老故事:男人去看医生导致他的膝盖因跑步而受伤,医生说'站起来'然后轻拍膝盖并说“这伤害了吗?”男人说'不,'医生:'如果我这样做了10K次......'


3
2018-03-12 02:21