在下面的代码中,我想测试是否已调用“DisplayHelper.displayAlert”。我依赖注入DisplayHelper
和AuthService
模拟对象,并使用PromiseKit
在我的ViewController中:
@IBAction func submitButtonPressed(sender: AnyObject) {
AuthService.updateUser(["zipcode": self.zipcodeTextField.text!])
.then { user -> Void in
// sucess code
}.error { error -> Void in
self.DisplayHelper.displayAlert("Zipcode Not Found", message: "We can't find that zipcode... please try again.", callingViewController: self)
}
}
以下是无效测试:
func testSubmitButtonServerCantFindZipcode() {
vc.zipcodeTextField.text = "00000"
vc.submitButtonPressed(self)
// called AuthService (passes)
XCTAssertEqual(authServiceMock.updateUserCalled, true)
// called displayAlert (fails because tests run before DisplayAlert is called)
XCTAssertEqual(displayHelperMock.displayAlertCalled, true)
}
如何在断言之前让测试等待所有代码执行?
答案 0 :(得分:2)
使用XCTest测试异步代码时,您需要使用XCTestExpectation
。
您可以像这样重写测试代码:
let e = expectationWithDescription("display alert")
waitForExpectationsWithTimeout(3) { error in
XCTAssertEqual(displayHelperMock.displayAlertCalled, true)
}
现在,唯一缺少的测试工作就是找到一个可以调用expectation.fulfill()
的地方。最合适的地方是AuthService
模拟, 成功和失败回调后。
如果我可以建议你一些东西,编写测试是否已经调用了某些方法并不是一种安全的测试方法,因为你只是测试实现而不是行为。
更好的方法是独立测试两个组件。测试AuthService
确保成功和失败路径都按预期执行,并DisplayHelper
确保警报视图实际添加到视图层次结构中。
This article可能是一个有用的地方,可以开始了解单元测试警报的方式,this post可以很好地了解为什么以及如何避免模拟。