我发现这个线程是一个引用:How do I wait for an asynchronously dispatched block to finish?并且正在使用该代码(在块内发出信号),等待我的线程完成测试之前完成。
然而,我的信号量从未表示它完成了......所以我逐步完成了代码,发现这个小片段内的代码永远不会运行:
dispatch_async(dispatch_get_main_queue(), ^{
[self removeDownloadSpinner];
block(callback);
});
当我进行单元测试时,dispatch_get_main_queue()不会触发吗?如果没有,你如何单元测试异步块?
编辑(这是一个更多的代码): 基本上我有一个“ServerRequest”类,它包含应用程序的所有传入/传出网络请求。一种方法是这样(完成块是typedeffed):
+(void)checkPlayerCode:(NSString *)playerCode completionHandler:(PlayerCompletionBlock)block {
[self addDownloadSpinner];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/players/%@",kBaseURL, playerCode]];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[ServerConnectionRequest sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSDictionary *p = [data objectFromJSONData];
Player *player = [[Player alloc] init];
player.last_name = [p objectForKey:@"last_name"];
if (!error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self removeDownloadSpinner];
block(player);
});
}
}];
}
从这样的uiviewcontroller调用:
[ServerRequest checkPlayerCode:codeCell.textField.text completionHandler:^(Player *p){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"wooo block" message:@"works" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}];
然而,dispatch_get_main_queue()块永远不会被触发。
答案 0 :(得分:1)
在单元测试中执行多线程代码没有问题,我在其中运行了各种调度代码。
当你说通过代码时,你的意思是你逐步使用调试器。如果是这样,并且您认为代码没有运行,因为调试器没有在块中停止,那么您必须记住这将在另一个线程上运行,并且您将需要一个断点来使其停止。
所以我会在块内分配断点。
其次,如果测试代码是从主线程运行的,那么这将无法工作,因为您无法在您所在的同一线程上异步执行某些代码。单元测试代码应该在后台线程上运行。
然后是执行时间问题。因为您正在运行异步块,所以它可能尚未执行。
异步调用的测试意味着上面的代码可能必须等待异步调用完成才能断言它可能做的任何事情。在这种情况下,您必须考虑它应该是同步而不是异步。
我需要显示更多代码: - )
答案 1 :(得分:1)
问题是你正在等待主线程上的信号量,同时尝试使用dispatch_async(dispatch_get_main_queue(),...)在主要步骤上执行一些代码。 尝试使用NSRunLoop的runUntilDate,比如
__block volatile bool loadComplete = false;
dispatch_async(dispatch_get_main_queue(), ^(..)
{
..
loadComplete = true;
});
NSDate* startTime = [NSDate date];
while ( !loadComplete )
{
NSDate* nextTry = [NSDate dateWithTimeIntervalSinceNow:0.1];
[[NSRunLoop currentRunLoop] runUntilDate:nextTry];
if ( [nextTry timeIntervalSinceDate:startTime] > ../* some appropriate time interval here */ )
STAssertTrue(false, @"TIMEOUT");
}
// Assertions here