我目前正在测试一些类的类,这些类可以进行诸如REST API调用之类的网络工作,并且Realm数据库在此过程中发生了变异。当我一次运行所有不同的测试时,就会出现竞赛条件(但是,当然,当我一一运行它们时,它们全部通过了)。如何可靠地使测试通过?
我试图像这样在GCD块中调用上述功能:
@t.content
我的一项测试仍然失败,因此我猜以上方法无效。我启用了Thread Sanitizer,它会不时报告出现竞争情况。
我无法发布代码,所以我正在寻找概念性的解决方案。
答案 0 :(得分:1)
通常是某种形式的依赖注入。它是DispatchQueue的内部公开var,带有队列的函数中的默认参数或构造函数参数。您只需要通过某种方法即可通过测试队列,该队列可以在需要时调度事件。
DispatchQueue.main.async
会将块异步调度到主队列上的被调用者,因此在您声明时无法保证。
示例(免责声明:我是从内存中键入内容的,因此它可能无法编译,但给出了提示):
// In test code.
struct TestQueue: DispatchQueue {
// make sure to impement other necessary protocol methods
func async(block: () -> Void) {
// you can even have some different behavior for when to execute the block.
// also you can pass XCTestExpectations to this TestQueue to be fulfilled if necessary.
block()
}
}
// In source code. In test, pass the Test Queue to the first argument
func doSomething(queue: DispatchQueue = DispatchQueue.main, completion: () -> Void) {
queue.async(block: completion)
}
其他测试异步和消除竞争条件的方法围绕着巧妙地实现XCTestExpectation。
如果您有权访问最终调用的完成块:
// In source
class Subject {
func doSomethingAsync(completion: () -> Void) {
...
}
}
// In test
func testDoSomethingAsync() {
let subject = Subject()
let expect = expectation(description: "does something asnyc")
subject.doSomethingAsync {
expect.fulfill()
}
wait(for: [expect], timeout: 1.0)
// assert something here
// or the wait may be good enough as it will fail if not fulfilled
}
如果您无权访问完成块,则通常意味着找到一种方法来注入或子类化测试双重对象,您可以将其设置为XCTestExpectation并最终在异步工作完成后达到期望。