Swift 在XCTest中:如何测试函数是否强制执行到主线程上

Swift 在XCTest中:如何测试函数是否强制执行到主线程上,swift,multithreading,xctest,Swift,Multithreading,Xctest,在UI类中,我有一个访问UI元素的方法,因此应该将其自身强制到主线程上。这里有一个最简单的例子来说明我的意思: class SomeUI { func doWorkOnUI() { guard Thread.isMainThread else { DispatchQueue.main.async { self.doWorkOnUI() } return

在UI类中,我有一个访问UI元素的方法,因此应该将其自身强制到主线程上。这里有一个最简单的例子来说明我的意思:

class SomeUI {

    func doWorkOnUI() {

        guard Thread.isMainThread else {

            DispatchQueue.main.async {

                self.doWorkOnUI()
            }
            return
        }

        print("Doing the work on UI and running on main thread")
    }
}
在测试中,当主线程上已经运行了
doWorkOnUI()
时,当然可以测试用例。我只是这样做:

func testWhenOnMainThread() {

    let testedObject = SomeUI()
    let expectation = XCTestExpectation(description: "Completed doWorkOnUI")

    DispatchQueue.main.async {
        testedObject.doWorkOnUI()
        expectation.fulfill()
    }

    wait(for: [expectation], timeout: 10.0)

    // Proceed to some validation
}
也就是说:强制执行到主线程上。等待它完成。做一些检查

但是如何测试相反的情况,即当从后台线程调用函数时,如何确保函数强制自己在主线程上运行?

例如,如果我做了如下操作:

...
    DispatchQueue.global(qos: .background).async {
        testedObject.doWorkOnUI()
        expectation.fulfill()
    }
...

我刚刚测试了从后台线程执行的函数。但我没有明确检查它是否在主线程上运行。当然,由于此函数访问UI元素,因此如果不强制在主线程上执行,它可能会崩溃。那么,“无崩溃”是这里唯一可测试的条件吗?还有更好的吗?

当后台有一个外部闭包,主线程有一个内部闭包时,我们需要两个测试:

  • 调用外部闭包。等待期望。等待0.01秒。检查是否执行了预期的工作
  • 调用外部闭包。这一次,不要等待期望。检查工作是否未执行
  • 要使用此模式,我认为您必须更改代码,以便测试可以直接调用外部闭包,而无需执行异步舞蹈。这表明您的设计太深,不做一些更改就无法进行测试


    为中间对象找到捕获闭包的方法。也就是说,不要直接调用
    DispatchQueue.global(qos:.background).async
    ,而是创建一个表示此操作的类型。然后,测试间谍版本可以捕获闭包,而不是将其分派到后台,以便您的测试可以直接调用它。然后,您可以使用异步等待来测试对主线程的回调。

    当后台有一个外部闭包,而主线程上有一个内部闭包时,我们需要两个测试:

  • 调用外部闭包。等待期望。等待0.01秒。检查是否执行了预期的工作
  • 调用外部闭包。这一次,不要等待期望。检查工作是否未执行
  • 要使用此模式,我认为您必须更改代码,以便测试可以直接调用外部闭包,而无需执行异步舞蹈。这表明您的设计太深,不做一些更改就无法进行测试

    为中间对象找到捕获闭包的方法。也就是说,不要直接调用
    DispatchQueue.global(qos:.background).async
    ,而是创建一个表示此操作的类型。然后,测试间谍版本可以捕获闭包,而不是将其分派到后台,以便您的测试可以直接调用它。然后可以使用异步等待测试对主线程的回调