Ios 如何在Swift 4中测试API?

Ios 如何在Swift 4中测试API?,ios,swift,xcode,unit-testing,Ios,Swift,Xcode,Unit Testing,我不熟悉单元测试。我已经测试了很多函数,我理解了这个概念,现在我想检查一下API。可能吗?我想是的。这是API: func sendRequest(path: String, params: Dictionary<String, Any>, showSpinner: Bool, completionHandler: @escaping (JSON, Error?) -> Void) { if Constants.IS_SIMULATOR { print(

我不熟悉单元测试。我已经测试了很多函数,我理解了这个概念,现在我想检查一下API。可能吗?我想是的。这是API:

func sendRequest(path: String, params: Dictionary<String, Any>, showSpinner: Bool, completionHandler: @escaping (JSON, Error?) -> Void) {
    if Constants.IS_SIMULATOR {
        print("Path: \(path)")
        print("Params: \(params)")
    }

    if Constants.APP_DEL.reachability?.connection == .none {
        completionHandler(JSON.null, NSError(domain: "No internet", code: 4, userInfo: nil))
        return
    }

    UIApplication.shared.isNetworkActivityIndicatorVisible = true

    if showSpinner {
        HUD.show(.labeledProgress(title: "Loading...", subtitle: "Please wait"))
    }

    if let jsonData = try? JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) {

        let url = NSURL(string: String(format: "%@%@", Constants.TEST_URL, path))!
        let request = NSMutableURLRequest(url: url as URL)
        request.httpMethod = "POST"
        request.httpBody = jsonData
        request.timeoutInterval = 120

        let task = URLSession.shared.dataTask(with: request as URLRequest){ data, response, error in
            DispatchQueue.main.async {
                if error != nil {
                    print(" ........ \(String(describing: error?.localizedDescription))")
                    UIApplication.shared.isNetworkActivityIndicatorVisible = false

                    if showSpinner {
                        HUD.flash(.labeledError(title: "Server issue", subtitle: "Invalid response"), delay: 2.0)
                    }

                    completionHandler(JSON.null, NSError(domain: "Invalid response", code: 420, userInfo: nil))
                    return
                }


                if (data?.isGzipped)! {
                    let decompressedData: Data = try! data!.gunzipped()
                    var json: JSON = JSON.null
                    do {
                        json = try JSON(data: decompressedData)
                    }
                    catch {
                        print(error)
                    }

                    if Constants.IS_SIMULATOR {
                        print("Response: \(json)")
                    }

                    UIApplication.shared.isNetworkActivityIndicatorVisible = false


                    if json["status"].int == 200 {
                        if showSpinner {
                            HUD.flash(.success, delay: 0.5)
                        }
                        completionHandler(json["data"], nil)
                    }
                    else if json["status"].int == 202 {
                        if showSpinner {
                            HUD.hide()
                        }
                        completionHandler(JSON.null, NSError(domain: json["message"].string!, code: json["status"].int!, userInfo: nil))
                    }
                    else if json["status"].int == 310 {
                        if showSpinner {
                            HUD.hide()
                        }
                        completionHandler(json["data"], nil)
                    }
                    else if json["status"].int == 403 {
                        if showSpinner {
                            HUD.hide()
                        }

                        GeneralHelper.sharedInstance.displayAlertMessage(titleStr: "Session expired", messageStr: "Kindly login again.")

                        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {

                            let domain = Bundle.main.bundleIdentifier!
                            UserDefaults.standard.removePersistentDomain(forName: domain)
                            UserDefaults.standard.synchronize()
                            Constants.APP_DEL.navC?.popToRootViewController(animated: false)
                        })
                        completionHandler(JSON.null, NSError(domain: json["message"].string!, code: json["status"].int!, userInfo: nil))
                    }
                    else {
                        if showSpinner {
                            HUD.flash(.labeledError(title: "", subtitle: json["message"].string!), delay: 2.0)
                        }
                        completionHandler(JSON.null, NSError(domain: json["message"].string!, code: json["status"].int!, userInfo: nil))
                    }
                }
                else {
                    let backToString = String(data: data!, encoding: String.Encoding.utf8) as String?
                    if Constants.IS_SIMULATOR {
                        print("Invalid response: \(String(describing: backToString))")
                    }
                    UIApplication.shared.isNetworkActivityIndicatorVisible = false


                    if showSpinner {
                        HUD.flash(.labeledError(title: "Server issue", subtitle: "Invalid response"), delay: 2.0)
                    }
                    completionHandler(JSON.null, NSError(domain: "Invalid response", code: 420, userInfo: nil))
                }
            }
        }

        task.resume()
    }
}

我在task上添加了一个断点,它会打印任务,但当我尝试移动到下一行时,它不会进入
Dispatch
,而是将我带出该断点,并在
task.resume()
处停止,因此我无法测试
错误
或预期的
结果
。有什么帮助吗?

这里有一个完成处理程序,api调用不同步。所以你应该在测试中等待结果。在Xcode中,您可以使用
XTestExpection

例如:

    func testAPIWorking()
        {

            let expectation = XCTestExpectation.init(description: "Your expectation")
            params = ["ios_token": "dq6YJkKwEx0:APA91bFeOTfJRFd5G78xMkv3AvjSLA7ey2dJxTZZAtMuuC50CqWILNzNjdgqVpNpDn7R4I0DLoydIVDYKubpGfgfu1bwz1H3VNU4D88ek8PJTAjxrd3CWkW78g0sNv6EZDLlTqUFeNxh", "api_token": "kfRSHL0bVP1fSmxNY3NfEGs8g0ktKCbTsPRRbfarh3a5ISIcZLu3qdK07MJ9H4rJ", "player_id": 8083]

            ServiceHelper.sharedInstance.sendRequest(path: "home", params: self.params, showSpinner: false) { (result, error) in

                if error != nil
                {
                    XCTFail("Fail")
                }
                // The request is finished, so our expectation
                expectation.fulfill()
            }
            // We ask the unit test to wait our expectation to finish.
            self.waitForExpectations(timeout: 20)
        }

天哪,请格式化你的代码。这不是C。您不能对此进行单元测试。如果你想测试这个,你需要一个集成测试。您只能对小的、独立的代码单元进行单元测试,而不能对依赖于服务器状态、internet连接等的部分进行单元测试。将实现的部分提取到单独的函数中(例如解析),然后您可以对这些部分进行单元测试。您是否通过Burp或Charles发送API请求?两者都有免费版本,允许您检查应用程序的请求并修改响应,以检查您的错误处理是否良好。抛出一个错误
对成员“期望(说明:)”的模糊引用
是抱歉,我忘记初始化期望。检查新的答案版本。是的,我知道我添加了期望值,但仍然不知道它是否有效。您是否使用特定的库进行测试?你是否在Xcode项目中正确设置了测试目标(它应该与你的应用程序不同)好的,我现在一切正常,但是如果状态代码返回200,我应该期待什么呢?
    func testAPIWorking()
        {

            let expectation = XCTestExpectation.init(description: "Your expectation")
            params = ["ios_token": "dq6YJkKwEx0:APA91bFeOTfJRFd5G78xMkv3AvjSLA7ey2dJxTZZAtMuuC50CqWILNzNjdgqVpNpDn7R4I0DLoydIVDYKubpGfgfu1bwz1H3VNU4D88ek8PJTAjxrd3CWkW78g0sNv6EZDLlTqUFeNxh", "api_token": "kfRSHL0bVP1fSmxNY3NfEGs8g0ktKCbTsPRRbfarh3a5ISIcZLu3qdK07MJ9H4rJ", "player_id": 8083]

            ServiceHelper.sharedInstance.sendRequest(path: "home", params: self.params, showSpinner: false) { (result, error) in

                if error != nil
                {
                    XCTFail("Fail")
                }
                // The request is finished, so our expectation
                expectation.fulfill()
            }
            // We ask the unit test to wait our expectation to finish.
            self.waitForExpectations(timeout: 20)
        }