在从 XCTestCase 调用的代码中使用 Dispatch.main 不起作用
Using Dispatch.main in code called from XCTestCase does not work
我有一个函数,它是同步函数的异步包装器。
同步函数如下:
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
循环会阻塞主线程(如果测试 运行s 在主线程上)。因此,通过 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
循环引入的问题,否则会阻塞线程。
我有一个函数,它是同步函数的异步包装器。
同步函数如下:
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
循环会阻塞主线程(如果测试 运行s 在主线程上)。因此,通过 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
循环引入的问题,否则会阻塞线程。