在单元测试中运行异步代码的问题

Posted

技术标签:

【中文标题】在单元测试中运行异步代码的问题【英文标题】:Issues running asynchronous code in unit tests 【发布时间】:2019-11-12 04:34:46 【问题描述】:

所以我在应用的单元测试中运行异步代码时遇到问题。我正在使用期望来等待代码在测试完成之前执行。异步代码通过 heroku 运行以获取值,然后应在应用程序中返回它们。通过这个单元测试,我试图确保通过 heroku 的连接正常工作。这是我的代码:

func test() 
    let url = "https://s.herokuapp.com/test"

    let params: [String: Any] = ["account_id": AppState.sharedInstance.user.accounttoken]

    let expectation = self.expectation(description: "Testing returning value")

    let totalBalance = ""
    Alamofire.request(url, method: .post, parameters: params)
        .validate(statusCode: 200..<300)
        .responseJSON  response in
            switch response.result 
            case .success:
                print("Returned with success")
            case .failure(let error):
                let status = response.response?.statusCode
                print("Failed, status: \(status)")
                print("Here is the error: \(error)")
            

            if let result = response.result.value 
                let balance = result as! NSDictionary
                let totalBalance = String(describing: "\(balance["Balance"]!)")
            
            XCTAssert(totalBalance != "")
            expectation.fulfill()
    
    waitForExpectations(timeout: 10, handler: nil)
    XCTAssert(totalBalance != "")

我感到困惑的原因是因为我没有错误让异步代码返回实际应用程序中的值。我在单元测试中只有等待时间问题。我收到两个失败错误,一个是 XCTAssert 不正确,一个是 waitForExpectations 超过 10 秒。如果这有助于找到解决方案,这里还会出现一些错误:

以下是文本形式的错误消息:

2019-07-01 09:44:38.181971-0400 Spotbirdparking[49677:4306598] TIC TCP 连接失败 [6:0x6000030b7cc0]: 3:-9816 Err(-9816) 2019-07-01 09:44:38.188607-0400 Spotbirdparking[49677:4306598] NSURLSession/NSURLConnection HTTP 加载失败 (kCFStreamErrorDomainSSL,-9816)2019-07-01 09:44:38.188819-0400 Spotbirdparking[49677:4306598] 任务 . HTTP 加载失败(错误 代码:-1200 [3:-9816]) 2019-07-01 09:44:38.189215-0400 Spotbirdparking[49677:4306623] 任务 . 以错误结束 - 代码: -1200 /Users/drewloughran/Desktop/SpotBird/SpotbirdparkingTests/SpotbirdparkingTests.swift:117: 错误:-[SpotbirdparkingTests.SpotbirdparkingTests test_stripe]: 异步等待失败:超过 10 秒的超时,与 未实现的期望:“测试条带返回值”。

我对 swift 也很陌生,因此对于此问题的任何帮助将不胜感激。

【问题讨论】:

两次提到XCTAssert(totalBalance != "")的原因是什么?另外,您确定任务在触发 10 秒超时之前完成吗? 代码中的 XCTAssert 两次只是我试图弄清楚我是否将它放在正确的位置,很抱歉在输入问题时错过了它。我也尝试过更长的等待时间,但这似乎并没有改变我遇到的错误。 【参考方案1】:

Drew,请先检查此错误。您的请求无法加载。

 HTTP load failed (error code: -1200 [3:-9816]) 2019-07-01 09:44:38.189215-0400 Spotbirdparking[49677:4306623] Task .<1> finished with error - code: -1200 

还要确保您用于实现预期的块正在执行。可能不是,这就是您的期望没有实现并且您的测试失败的原因。

另外,from this documentation 我可以看到您的验证与自动验证用例相交。这是多余的。

 Response Validation
By default, Alamofire treats any completed request to be successful, regardless of the content of the response. Calling validate before a response handler causes an error to be generated if the response had an unacceptable status code or MIME type.

Manual Validation
Alamofire.request("https://httpbin.org/get")
    .validate(statusCode: 200..<300)
    .validate(contentType: ["application/json"])
    .response  response in
        switch response.result 
        case .success:
            print("Validation Successful")
        case .failure(let error):
            print(error)
        
    
Automatic Validation
Automatically validates status code within 200...299 range, and that the Content-Type header of the response matches the Accept header of the request, if one is provided.

Alamofire.request("https://httpbin.org/get").validate().responseJSON  response in
    switch response.result 
    case .success:
        print("Validation Successful")
    case .failure(let error):
        print(error)
    

祝你好运!

【讨论】:

感谢您对验证的帮助。我有一个关于请求失败错误的问题。您是否认为这是一个单元测试错误,因为对 Alamofire 的类似请求正在我的应用中运行?【参考方案2】:

您不应该通过实际联网来测试您的 Alamofire 调用。这会导致您每次测试时都访问网络;它不可靠(网络可能出现故障)并且没有必要。我们知道网络的作用!您也不必测试 Alamofire;测试不是你的,而且你知道它的作用。因此,您应该重构代码以进行测试并模拟网络调用。

【讨论】:

以上是关于在单元测试中运行异步代码的问题的主要内容,如果未能解决你的问题,请参考以下文章

对于异步代码的单元测试

Mocha 单元测试框架简介

为啥不能识别“异步无效”单元测试?

使用 Moq 模拟单元测试的异步方法

如何使用异步路由进行 Ember 单元测试?

单元测试不了解 XCTest 期望的异步 UI 代码?