9

我有多个测试,每个测试都在使用给定参数测试不同结果的相同异步方法。

我发现对于异步测试,我们必须声明一个期望,等待期望,然后实现期望。这可以。每个测试单独完成时都能正常运行,但是当我尝试运行整个测试类时,一些测试通过,而另一些测试在正常运行和通过时崩溃或失败。

我在网上到处寻找“带有期望的 swift 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)
      }
}

据我所知,这是对期望的正确使用,每个测试都遵循相同的模式

根据 Rob 的要求,我将在此处提供一个 MCVE https://bitbucket.org/chirone/mcve_test 测试类使用模拟 API 管理器,但是当我使用真实的 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 有助于解释我的问题。

4

3 回答 3

4

重构代码如下。

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)
  }
}

如果您仍然遇到以下崩溃,这意味着您的异步代码完成处理程序正在调用多次。并在那里通过多次调用expect.fulfill() 。这是不允许的。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'API violation - multiple calls made to -[XCTestExpectation fulfill] for testing for empty fields.'

对于期望,fulfill()应该只调用一次。如果有一些罕见的场景并且您需要多次调用expect.fulfill(),则设置以下属性。

expectedFulfillmentCount

请参考以下链接 https://developer.apple.com/documentation/xctest/xctestexpectation/2806572-expectedfulfillmentcount?language=objc

于 2019-03-19T18:09:52.110 回答
2

是否可以等待多重期望;是的。这是显示这一点的 XCTestCase 方法的签名。

func wait(for: [XCTestExpectation], timeout: TimeInterval)

有一个版本还可以确保以与它们在for:数组中出现的顺序相同的顺序实现期望。

在 XCode->Window->Documentation and API Reference 中查看 Apple 提供的文档,然后搜索 XCTestCase。

于 2017-05-30T17:14:37.727 回答
0

如果您在一个 XCTestCase 中有多个测试(方法),请不要使用

let expectation = expectation(description: "")

相反,使用

let expectation = XCTestExpectation(description: "")

self.expectaion()XCTestCase 测试之间共享。在某些情况下,它会带来奇怪的行为。例如,即使您满足预期零次,您也会收到 API 违规错误。

于 2020-06-03T14:14:41.047 回答