[英]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
服务协议。 即AlamoFireLoginClient
、 URLSessionLoginClient
、 FirebaseLoginClient
等。
我希望我有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.