Swift中waitForExpectations未按预期工作,Swift4单元测试问题求助
搞定你的Swift 4单元测试异步问题
嘿,我一眼就瞅出你这测试卡壳的原因了——你把异步方法当成同步方法来处理啦!
你想想,retrieveAccessKeys()明显是个异步执行的操作(不然你也不会想着加sleep(5)等它),但你直接同步调用let keys = sut.retrieveAccessKeys(),这时候异步任务还没跑完呢,keys肯定是nil,直接就触发XCTFail了,你的expectation连被fulfill的机会都没有,最后waitForExpectations自然会超时报错。
怎么改?看这几步
第一步:先把被测方法的异步调用搞对
首先,你的sut.retrieveAccessKeys()得支持异步回调才行——异步方法不能直接同步返回结果,得用闭包把结果传出来。比如被测对象的方法应该是这样的(如果还不是,得先改它):
func retrieveAccessKeys(completion: @escaping (AccessKeys?) -> Void) { // 模拟异步操作,比如网络请求、本地异步读取 DispatchQueue.global().asyncAfter(deadline: .now() + 1) { // 这里替换成真实的异步逻辑,返回keys或者nil completion(AccessKeys()) } }
第二步:重写你的单元测试
把测试改成异步回调的方式,在回调里处理结果,同时管理好XCTestExpectation:
func testRetrieveAccessKeys() { let expectation = self.expectation(description: "Obtain access keys") sut.retrieveAccessKeys { retrievedKeys in guard let keys = retrievedKeys else { XCTFail("ERROR: Failed obtaining access keys") expectation.fulfill() // 哪怕失败也要fulfill,别让测试超时 return } // 这里还能加更多断言,比如验证keys的具体字段是否符合预期 XCTAssertNotNil(keys, "Access keys should not be nil") expectation.fulfill() } waitForExpectations(timeout: 5) { error in if let error = error { print("Wait error: \(error.localizedDescription)") } } }
几个重要的小提醒
- 别再用
sleep()了!:这是单元测试的大忌,不仅拖慢测试速度,还会因为异步操作的执行时间不稳定导致测试偶尔翻车。XCTestExpectation就是用来优雅等待异步任务完成的,用它就对了。 - 无论成功失败都要fulfill:就算回调里返回
nil触发了XCTFail,也要记得调用expectation.fulfill(),不然waitForExpectations会一直等到超时,白白浪费时间还输出多余错误。 - 如果被测方法没回调:那你得先改造
sut的retrieveAccessKeys(),让它支持异步回调(或者用通知、Combine这类方式通知结果),不然根本没法正确测试异步操作。
内容的提问来源于stack exchange,提问作者user7684436
相关产品推荐
相关产品推荐

