当前位置: 首页 > 面试题库 >

如何在运行测试之前让XCTest等待setUp中的异步调用?

宰父嘉胜
2023-03-14
问题内容

我正在用Xcode 6编写集成测试,以配合单元测试和功能测试。XCTest有一个setUp()方法,该方法在每次测试之前都会被调用。大!

它还具有XCTestException,可以让我编写异步测试。也很棒!

但是,我想在每次测试之前用测试数据填充测试数据库,而setUp在异步数据库调用完成之前才开始执行测试。

有没有办法让setUp等到数据库准备好后再运行测试?

这是我现在所做的一个示例。由于setUp在数据库完成填充之前返回,因此我必须在每个测试中重复很多测试代码:

func test_checkSomethingExists() {

    let expectation = expectationWithDescription("")
    var expected:DatabaseItem

    // Fill out a database with data. 
    var data = getData()
    overwriteDatabase(data, {
      // Database populated.
      // Do test... in this pseudocode I just check something...
      db.retrieveDatabaseItem({ expected in

        XCTAssertNotNil(expected)

        expectation.fulfill()
      })
    })

    waitForExpectationsWithTimeout(5.0) { (error) in
        if error != nil {
            XCTFail(error.localizedDescription)
        }
    }

}

这就是我想要的:

class MyTestCase: XCTestCase {

    override func setUp() {
        super.setUp()

        // Fill out a database with data. I can make this call do anything, here
        // it returns a block.
        var data = getData()
        db.overwriteDatabase(data, onDone: () -> () {

           // When database done, do something that causes setUp to end 
           // and start running tests

        })        
    }

    func test_checkSomethingExists() {

        let expectation = expectationWithDescription("")
        var expected:DatabaseItem


          // Do test... in this pseudocode I just check something...
          db.retrieveDatabaseItem({ expected in

            XCTAssertNotNil(expected)

            expectation.fulfill()
        })

        waitForExpectationsWithTimeout(5.0) { (error) in
            if error != nil {
                XCTFail(error.localizedDescription)
            }
        }

    }

}

问题答案:

有两种运行异步测试的技术。XCTestExpectation和信号量。如果在中执行异步操作setUp,则应使用信号量技术:

override func setUp() {
    super.setUp()

    // Fill out a database with data. I can make this call do anything, here
    // it returns a block.

    let data = getData()

    let semaphore = DispatchSemaphore(value: 0)

    db.overwriteDatabase(data) {

        // do some stuff

        semaphore.signal()
    }

    semaphore.wait()
}

请注意,要使其正常工作,该onDone块不能在主线程上运行(否则将导致死锁)。

如果此onDone块在主队列上运行,则可以使用运行循环:

override func setUp() {
    super.setUp()

    var finished = false

    // Fill out a database with data. I can make this call do anything, here
    // it returns a block.

    let data = getData()

    db.overwriteDatabase(data) {

        // do some stuff

        finished = true
    }

    while !finished {
        RunLoop.current.run(mode: .default, before: Date.distantFuture)
    }
}

这是一个非常低效的模式,但是根据overwriteDatabase实现方式的不同,可能有必要

注意,仅当您知道该onDone块在主线程上运行时才使用此模式(否则,您将必须对finished变量进行一些同步)。



 类似资料:
  • 我有一个方法如下所示: 我试图这样进行单元测试: 在完成模拟的LookUpIdAsync之前,将调用我的断言。在我的普通代码中,这正是我想要的。但是对于我的单元测试,我不希望这样。 我正在使用BackgroundWorker转换为Async/Await。对于后台工作人员,这项功能正常运行,因为我可以等待后台工作人员完成。 但是似乎没有办法等待异步无效方法... 如何对该方法进行单元测试?

  • 问题内容: 最近,我不得不更正Web应用程序(我没有创建)中的安全性问题。安全问题是,它正在使用非仅限HTTP的cookie。因此,我不得不将session- cookie设置为仅http-,这意味着您无法再从javascript中读取(设置)cookie的值。到目前为止,接缝都很容易。 更深层的问题是,使用的Web应用程序 在一百万个地方 。 因此,为了不必重写“一百万行代码”,我不得不创建一个

  • 我们有一个async/await方法,它通过实体框架调用存储的过程,该框架由同步方法调用。 需要很长的时间来执行,这可能就是我们编写async/await的原因,它可以被多个地方使用。 我知道我们不应该混合异步和同步调用,但假设我们有这种情况并且我们正在使用 从同步方法 调用异步方法 GetLoanDataAsync,我理解该方法 - 将在后台线程上运行。 我的问题是,如果我们有一个异步方法< c

  • 问题内容: 据我了解,在ES7 /ES2016中,将多个in放在代码中的工作方式类似于带有promise的链接,这意味着它们将一个接一个地执行而不是并行执行。因此,例如,我们有以下代码: 我是否正确理解仅在完成时才会调用?并行调用它们的最优雅方式是什么? 我想在Node中使用它,所以也许有一个异步库解决方案? 编辑:我对这个问题提供的解决方案不满意:减速是由于异步生成器中非并行等待Promise的

  • 问题内容: 我有一个在另一个类中启动异步任务,然后应该等待结果。 问题是方法将在方法运行完成后立即完成,对吗? 这意味着,通常,在启动异步任务后,它将立即关闭,并且不再在那里接收结果。 如何使以上代码段正常工作?开始任务后,我已经尝试放入(任意持续时间)。似乎可以正常工作。 但这绝对不是一个干净的解决方案。也许甚至有一些严重的问题。 有更好的解决方案吗? 问题答案: 使用标准类代替,从回调启动异步

  • 我正在尝试为我的颤振应用程序编写一个测试。我为其编写测试的函数返回未来,因此我使用wait。 但是,只要使用任何WAIT语句,我就会得到MissingPluginException错误。 我尝试更改依赖项版本,但没有帮助。在GitHub上找不到与此相关的颤振问题或StackOverFlow。 预计工作正常。 获取错误: MissingPluginException(在channel plugins