gpt4 book ai didi

objective-c - 完成时调用主队列的单元测试异步队列模式

转载 作者:太空狗 更新时间:2023-10-30 03:08:54 26 4
gpt4 key购买 nike

这和我之前的question有关, 但足够不同,我想我会把它扔进一个新的。我有一些代码在自定义队列上运行异步,然后在完成时在主线程上执行一个完成 block 。我想围绕这个方法编写单元测试。我在 MyObject 上的方法如下所示。

+ (void)doSomethingAsyncThenRunCompletionBlockOnMainQueue:(void (^)())completionBlock {

dispatch_queue_t customQueue = dispatch_queue_create("com.myObject.myCustomQueue", 0);

dispatch_async(customQueue, ^(void) {

dispatch_queue_t currentQueue = dispatch_get_current_queue();
dispatch_queue_t mainQueue = dispatch_get_main_queue();

if (currentQueue == mainQueue) {
NSLog(@"already on main thread");
completionBlock();
} else {
dispatch_async(mainQueue, ^(void) {
NSLog(@"NOT already on main thread");
completionBlock();
});
}
});

为了额外的安全,我加入了主队列测试,但它总是命中 dispatch_async。我的单元测试如下所示。

- (void)testDoSomething {

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

void (^completionBlock)(void) = ^(void){
NSLog(@"Completion Block!");
dispatch_semaphore_signal(sema);
};

[MyObject doSomethingAsyncThenRunCompletionBlockOnMainQueue:completionBlock];

// Wait for async code to finish
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);

STFail(@"I know this will fail, thanks");
}

我创建了一个信号量以阻止测试在异步代码完成之前完成。如果我不需要完成 block 在主线程上运行,这会很好用。然而,正如一些人在我上面链接的问题中指出的那样,测试在主线程上运行然后我将完成 block 排入主线程的事实意味着我将永远挂起。

从异步队列调用主队列是一种我经常看到的用于更新 UI 等的模式。有没有人有更好的模式来测试回调主队列的异步代码?

最佳答案

有两种方法可以让 block 分派(dispatch)到主队列运行。第一个是通过 dispatch_main,正如 Drewsmits 所提到的。然而,正如他还指出的那样,在您的测试中使用 dispatch_main 存在一个大问题:它永远不会返回。它只会坐在那里等待运行任何在永恒的剩余时间里出现的障碍。正如您想象的那样,这对单元测试没有太大帮助。

幸运的是,还有另一种选择。在 dispatch_main man pageCOMPATIBILITY 部分中,它是这样说的:

Cocoa applications need not call dispatch_main(). Blocks submitted to the main queue will be executed as part of the "common modes" of the application's main NSRunLoop or CFRunLoop.

换句话说,如果您在 Cocoa 应用程序中,调度队列会被主线程的 NSRunLoop 耗尽。所以我们需要做的就是在等待测试完成时保持运行循环运行。它看起来像这样:

- (void)testDoSomething {

__block BOOL hasCalledBack = NO;

void (^completionBlock)(void) = ^(void){
NSLog(@"Completion Block!");
hasCalledBack = YES;
};

[MyObject doSomethingAsyncThenRunCompletionBlockOnMainQueue:completionBlock];

// Repeatedly process events in the run loop until we see the callback run.

// This code will wait for up to 10 seconds for something to come through
// on the main queue before it times out. If your tests need longer than
// that, bump up the time limit. Giving it a timeout like this means your
// tests won't hang indefinitely.

// -[NSRunLoop runMode:beforeDate:] always processes exactly one event or
// returns after timing out.

NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:10];
while (hasCalledBack == NO && [loopUntil timeIntervalSinceNow] > 0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:loopUntil];
}

if (!hasCalledBack)
{
STFail(@"I know this will fail, thanks");
}
}

关于objective-c - 完成时调用主队列的单元测试异步队列模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7817605/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com