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

Posted

技术标签:

【中文标题】在 XCTest 中:如何测试函数是不是强制执行到主线程【英文标题】:In XCTest: how to test that a function forced execution onto main thread在 XCTest 中:如何测试函数是否强制执行到主线程 【发布时间】:2020-11-15 17:51:34 【问题描述】:

在 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 元素,因此如果不强制在主线程上,预期它会崩溃。那么“没有崩溃”是这里唯一可测试的条件吗?有没有更好的?

【问题讨论】:

【参考方案1】:

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

    调用外部闭包。等待期望。等待 0.01 秒。检查是否执行了预期的工作。 调用外部闭包。这一次,不要等待期望。检查工作是否未执行。

要使用这种模式,我认为您必须更改代码,以便测试可以直接调用外部闭包,而无需进行异步舞蹈。这表明您的设计太深而无法在不进行一些更改的情况下进行测试。

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

【讨论】:

以上是关于在 XCTest 中:如何测试函数是不是强制执行到主线程的主要内容,如果未能解决你的问题,请参考以下文章

XCTest 睡眠()函数?

xctest - 如何测试是不是在按下按钮时加载新视图

XCTest:如何检查异步元素是不是存在

如何在 Xcode 中配置和运行目标 C 测试用例--XCTest

如何对强制展开进行单元测试

XCTest 如何执行 segue 呈现模态视图并测试presentedViewController