Chi*_*one 5 testing asynchronous swift xctestexpectation
我有多个测试,每个测试都使用给定参数测试相同的异步方法以获取不同的结果。
我发现对于异步测试,我们必须声明一个期望,等待期望,并实现期望。这可以。每个测试单独完成时都可以正常工作,但是当我尝试运行整个测试类时,某些测试会通过,而其他一些则在正常运行并通过时会崩溃或失败。
我在网上四处寻找“用期望迅速进行3次多重测试”,每个解释期望的人都只能在一个测试方法中找到一个例子。在同一个类的多个方法中不可能有期望吗?
测试示例如下:
func testLoginWrongUsernameOrPasswordFailure() {
let viewModel = LoginViewModel()
let loginAPI = APIManager()
let expect = expectation(description: "testing for incorrect credentials")
viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in
do {
try loginCompletion()
XCTFail("Wrong Login didn't error")
expect.fulfill()
} catch let error {
XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
expect.fulfill()
}
})
waitForExpectations(timeout: 10) { error in
XCTAssertNil(error)
}
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这是对期望值的正确使用,并且每个测试都遵循相同的模式
根据Rob的要求,我将在此处提供MCVE https://bitbucket.org/chirone/mcve_test 测试类使用模拟API管理器,但是当我使用真实的API管理器进行测试时,仍然会发生错误。
作为对代码的解释,视图模型与给定的API管理器进行通信,后者调用服务器并向视图模型返回响应,以供他解释错误或成功。
第一个测试将测试空白字段,而视图模型会验证空白字段,而不是APIManager。第二个测试测试不正确的用户名和密码第三个测试测试有效的用户名和密码
分别运行的三个测试将运行良好,但是当运行整个文件时,由于以下原因,我会收到SIGABRT错误:
XCTAssertEqual失败:(“” Optional(MCVE.LoginError.wrongCredentials)“)不等于(”“ Optional(MCVE.LoginError.emptyFields)”)-
***-[XCTestExpectation满足],/ Library / Caches / com.apple.xbs / Sources / XCTest_Sim / XCTest-12124 / Sources / XCTestFramework / Async / XCTestExpectation.m:101中的断言失败
***由于未捕获的异常“ NSInternalInconsistencyException”而终止应用程序,原因:“违反API-多次调用-[XCTestExpectation履行]以测试空字段。”
SIGABRT通常发生在第二种测试方法上,如果您点击播放,则它在XCTest方法之一上失败,声称它得到的错误不是预期的错误。
我希望MCVE可以帮助解释我的问题。
如果您在一个 XCTestCase 中有多个测试(方法),请不要使用
let expectation = expectation(description: "")
Run Code Online (Sandbox Code Playgroud)
相反,使用
let expectation = XCTestExpectation(description: "")
Run Code Online (Sandbox Code Playgroud)
它self.expectaion()在 XCTestCase 测试之间共享。在某些情况下,它会带来奇怪的行为。例如,即使您满足期望零次,您也可能会收到 API 违规错误。
重构代码如下。
func testLoginWrongUsernameOrPasswordFailure() {
let viewModel = LoginViewModel()
let loginAPI = APIManager()
let expect = expectation(description: "testing for incorrect credentials")
viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in
do {
try loginCompletion()
XCTFail("Wrong Login didn't error")
} catch let error {
XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
}
expect.fulfill()
})
waitForExpectations(timeout: 10) { error in
XCTAssertNil(error)
}
}
Run Code Online (Sandbox Code Playgroud)
如果您仍然遇到以下崩溃,则意味着异步代码的完成处理程序正在调用多次。然后多次调用expect.fulfill() 。这是不允许的。
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'API violation - multiple calls made to -[XCTestExpectation fulfill] for testing for empty fields.'
Run Code Online (Sandbox Code Playgroud)
对于期望的fill()应该只调用一次。如果存在一些罕见的情况,并且您需要多次调用expect.fulfill() ,则设置以下属性。
expectedFulfillmentCount
Run Code Online (Sandbox Code Playgroud)
是否可以等待多重期待;是的。这是显示这一点的 XCTestCase 方法的签名。
func wait(for: [XCTestExpectation], timeout: TimeInterval)
Run Code Online (Sandbox Code Playgroud)
有一个版本还确保按照数组中出现的顺序满足期望for:。
请参阅Apple提供的文档,在XCode->Window->Documentation and API Reference中,然后搜索XCTestCase。