繁体   English   中英

iOS swift 单元测试 - 如何测试 function 调用 Z8A5DA52ED1264477D35AZ9E70A8A5

[英]iOS swift unit testing - How to test function that makes an api call?

我正在尝试使用 TDD 创建一个 iOS 应用程序。 我有一个 function 进行 api 调用。 你能解释一下在这个 function 中要测试什么吗?

Function 获取用户名、密码和闭包作为参数。 它应该进行 api 调用,并在收到响应后调用 completionHandler。

func login(username: String,
           password: String,
           completionHandler: @escaping (_ result: Result<LoginResponse, Error>) -> Void) {
    // TODO
}

PS:我正在使用 Alamofire 进行网络连接

这取决于您要测试的login use case的“部分”,即您项目的具体 HTTPClient? (URLSession、Alamofire 等),或者这个服务的实现,但我会给你一些建议。

尝试使用 DI(依赖注入)来准备您的声明(类、结构、函数......)以使用协议或 inheritance(协议将是大多数情况下的最佳选择)进行测试。 然后,评估所有可能的响应情况。 我为登录服务用例演示做了一个简单的实现。

//
//  Created by Wilmer Barrios.
//

import XCTest

// Business Logic
struct LoginResponse {
    let succeed: Bool
}

protocol LoginService {
    func login(username: String, password: String, completion: @escaping (Result<LoginResponse, Error>) -> Void)
}

// Implementation
class LoginController {
    
    // Presented values
    var presentedSucceedMessage: String?
    var presentedErrorMessage: String?
    
    // Elements (Could be textfields)
    var username: String = ""
    var password: String = ""
    
    private let service: LoginService
    
    init(service: LoginService) {
        self.service = service
    }
    
    func login() {
        service.login(username: username, password: password, completion: { [weak self] result in
            if let response = try? result.get(), response.succeed {
                self?.presentedSucceedMessage = "Login succeed!"
            } else {
                self?.presentedErrorMessage = "Login error!"
            }
        })
    }
}

class LoginControllerTests: XCTestCase {

    func test_init_doesNotLogin() {
        let (_, service) = makeSUT()
        XCTAssertEqual(service.callCount, 0)
    }
    
    func test_login_doesLoadService() {
        let (sut, service) = makeSUT()
        sut.login()
        
        XCTAssertEqual(service.callCount, 1)
    }
    
    func test_loginSucceed_presentsSucceedMessage() {
        let (sut, service) = makeSUT()

        sut.login()
        service.complete(result: .success(makeLoginResponse()))
        
        XCTAssertEqual(sut.presentedSucceedMessage, "Login succeed!")
        XCTAssertNil(sut.presentedErrorMessage)
    }
    
    func test_loginError_presentsErrorMessage() {
        let (sut, service) = makeSUT()

        sut.login()
        service.complete(result: .success(makeLoginResponse(succeed: false)))
        
        XCTAssertEqual(sut.presentedErrorMessage, "Login error!")
        XCTAssertNil(sut.presentedSucceedMessage)
    }
    
    func test_loginFailed_presentsErrorMessage() {
        let (sut, service) = makeSUT()

        sut.login()
        service.complete(result: .failure(makeError()))
        
        XCTAssertEqual(sut.presentedErrorMessage, "Login error!")
        XCTAssertNil(sut.presentedSucceedMessage)
    }
    
    // MARK: Helpers
    private func makeError() -> Error {
        return NSError(domain: "anyError", code: 1)
    }
    
    private func makeLoginResponse(succeed: Bool = true) -> LoginResponse {
        return LoginResponse(succeed: succeed)
    }
    
    private func makeSUT() -> (sut: LoginController, service: LoginServiceMock) {
        let service = LoginServiceMock()
        let sut = LoginController(service: service)
        return (sut, service)
    }
    
    private class LoginServiceMock: LoginService {
        var callCount: Int = 0
        private var completion: ((Result<LoginResponse, Error>) -> Void)?
        
        func login(username: String, password: String, completion: @escaping (Result<LoginResponse, Error>) -> Void) {
            callCount += 1
            self.completion = completion
        }
        
        // Helpers
        func complete(result: Result<LoginResponse, Error>) {
            completion?(result)
        }
    }

}

在这个例子中,你可以请求任何登录服务,它可以是你自己的 API、Firebase、任何 SDK,甚至是本地的,你只需要使服务符合LoginService服务协议。 AlamoFireLoginClientURLSessionLoginClientFirebaseLoginClient等。

我希望我有所帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM