swift - 在从 XCTestCase 调用的代码中使用 Dispatch.main 不起作用
问题描述
我有一个函数是围绕同步函数的异步包装器。
同步函数如下:
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
completion
当我从不运行时调用它。
在 XCode 中完成单元测试的方式和主线程之间是否存在某种不正当的交互?
我在网上找不到关于此的文档。
我必须使用主线程进行回调,因为它与 Gui 交互。
我的测试用例看起来像:
func testAsyncBar() throws {
var run = true
func stopThisThing(ints: [Int]) {
run = false
}
Foo.asyncBar(completion: stopThisThing)
while run {
print ("Running...")
usleep(100000)
}
}
最后的繁忙循环永远不会停止。
解决方案
您的测试while
循环将阻塞主线程(如果测试在主线程上运行)。因此,通过调度的闭包DispatchQueue.main.async
永远不会运行,并且您的run
布尔值永远不会被重置。这会导致死锁。Thread.isMainThread
您可以通过打印或添加类似的测试来确认这一点dispatchPrecondition(condition: .onQueue(.main))
。
幸运的是,单元测试有一个简单的机制可以避免这种死锁。如果您希望单元测试等待某个异步过程,请使用XCTestExpectation
:
func testAsyncBar() throws {
let e = expectation(description: "asyncBar")
func stopThisThing(ints: [Int]) {
e.fulfill()
}
Foo.asyncBar(completion: stopThisThing)
waitForExpectations(timeout: 5)
}
这避免了循环引入的问题while
,否则会阻塞线程。
请参阅使用期望测试异步操作。
推荐阅读
- reactjs - 使用 useEffect 和 useState 在查看时增加数字
- python - 从 Pandas 数据类型获取 Python 类型
- iis - 如何使用 IIS 将所有请求重定向到网络服务器上的特定文件夹
- java - 无法在 Kotlin 中使用协程(未解决的参考)
- stimulsoft - 没有加载 StimulSoft Report svgs 的问题
- c# - .Net Core 3.1 的池化数据库上下文
- styled-components - 带有样式组件的滑动按钮样式
- javascript - Mongodb 注册重新运行成功,但是当我登录用户时它返回错误。我正在使用 Postman 来测试 Api
- javascript - 为什么使用map、forEach和for循环将数组插入数据库时的顺序不同
- android - Android CameraX 分析器,启用手电筒没有任何作用