在从XCTestCase调用的代码中使用Dispatch.main无效 [英] Using Dispatch.main in code called from XCTestCase does not work

查看:53
本文介绍了在从XCTestCase调用的代码中使用Dispatch.main无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数,它是一个围绕同步函数的异步包装器.

I have a function that is a async wrapper around a synchronous function.

同步功能类似于:

class Foo {
    class func bar() -> [Int] {
        return [1,2,3]
    }

    class func asyncBar(completion: @escaping ([Int]) -> Void) {
        DispatchQueue.global(qos: .userInitiated).async {
            let intArray = bar()
            DispatchQueue.main.async {
                completion(intArray)
            }
        }
    }
}

当我从 XCTestCase 调用它时,完成无法运行.

When I call it from a XCTestCase completion does not run.

在XCode中进行单元测试的方式与主线程之间是否存在某种有害的交互作用?

Is there some sort of perverse interaction between the way unit tests are done in XCode and the main thread?

我在网上找不到关于此的文档.

I can find no documentation on the Web about this.

在与Gui交互时,我必须使用主线程进行回调.

I have to use the main thread for the callback as it interacts with the Gui.

我的测试用例看起来像:

My test case looks something like:

func testAsyncBar() throws {
    var run = true
    func stopThisThing(ints: [Int]) {
        run = false
    }
    Foo.asyncBar(completion: stopThisThing)
    while run {
        print ("Running...")
        usleep(100000)
    }
}

繁忙的循环永远不会停止.

The busy loop at the end never stops.

推荐答案

您的测试的 while 循环将阻塞主线程(如果测试在主线程上运行).这样,通过 DispatchQueue.main.async 调度的闭包将永远无法运行,并且您的 run 布尔值也永远不会重置.这将导致死锁.您可以通过打印 Thread.isMainThread 或添加诸如 dispatchPrecondition(condition:.onQueue(.main))之类的测试来确认这一点.

Your test’s while loop will block the main thread (if the test runs on the main thread). As such, the closure dispatched via DispatchQueue.main.async can never run, and your run Boolean will never get reset. This results in a deadlock. You can confirm this by printing Thread.isMainThread or adding a test like dispatchPrecondition(condition: .onQueue(.main)).

幸运的是,单元测试具有避免这种死锁的简单机制.如果希望单元测试等待某些异步过程,请使用 XCTestExpectation :

Fortunately, unit tests have a simple mechanism that avoids this deadlock. If you want unit test to wait for some asynchronous process, use an XCTestExpectation:

func testAsyncBar() throws {
    let e = expectation(description: "asyncBar")

    func stopThisThing(ints: [Int]) {
        e.fulfill()
    }

    Foo.asyncBar(completion: stopThisThing)

    waitForExpectations(timeout: 5)
}

这避免了 while 循环所引入的问题,这些问题原本会阻塞线程.

This avoids problems introduced by the while loop that otherwise blocked the thread.

请参见测试具有期望的异步操作.

这篇关于在从XCTestCase调用的代码中使用Dispatch.main无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆