我正在用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,则应使用信号量技术:
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
如果此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实现方式的不同,可能有必要
overwriteDatabase
注意,仅当您知道该onDone块在主线程上运行时才使用此模式(否则,您将必须对finished变量进行一些同步)。
finished