swift - 单元测试中的竞争条件

标签 swift unit-testing race-condition xctest

我目前正在测试一些类,这些类执行 REST API 调用等网络操作,并且 Realm 数据库在此过程中发生了变化。当我同时运行所有不同的测试时,会出现竞争条件(当然,当我一个一个地运行它们时,它们都会通过)。我怎样才能可靠地通过测试?

我试过像这样在 GCD block 中调用提到的函数:

DispatchQueue.main.async {
    self.function.start()
}

我的一个测试仍然失败,所以我猜上面的方法没有用。我已启用 Thread Sanitizer,它会不时报告出现竞争条件。

我无法发布代码,所以我正在寻找概念性解决方案。

最佳答案

通常是某种形式的依赖注入(inject)。它可以是 DispatchQueue 的内部公开 var,带有队列的函数中的默认参数,或者构造函数参数。您只需要一些方法来传递一个测试队列,该队列在您需要时分派(dispatch)事件。

DispatchQueue.main.async 会将 block 异步安排到主队列上的被调用方,因此在您进行断言时无法保证。

示例(免责声明:我是凭内存输入的,所以它可能无法编译,但它给出了想法):

// 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。

如果您有权访问最终调用的完成 block :

// 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
}

如果您无权访问完成 block ,这通常意味着找到一种方法来注入(inject)或子类化您可以设置 XCTestExpectation 的测试替身,并最终在异步工作完成时满足预期。

关于swift - 单元测试中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51097682/

相关文章:

javascript - 这对 AJAX 请求是否存在竞争条件?

c++ - 为什么在 child 被破坏后 parent 的方法仍然存在

ios - Swift 后台同步管理器

ios - 在 Swift 中设置自动布局约束,以使用可变的垂直空间填充不同的屏幕尺寸

angular - 未捕获的类型错误 : Cannot read property 'teams' of undefined thrown - Karma

unit-testing - 将服务注入(inject) Ember 测试

ios - 字幕单元格的 Swift 自动行高

swift - 获取用于创建 SCNNode 的 SCNSphere 的半径

c# - Redis 缓存的最小起订量单元测试

C使用管道传输数据以使用共享内存写入文件