Я хотел бы написать модульные тесты для моего сетевого кода.
Я бы хотел сказать, что мой хост настроен правильно.
В моем сетевом коде используются общие шаблоны, поэтому я могу передать ожидаемую модель ответа на основе конечной точки, которую я вызываю.
Мой XCTTestCase
выглядит так:
@testable import Home
import XCTest
class APIClientTests: XCTestCase {
var sut: APIClient!
var mockURLSession: MockURLSession!
override func setUp() {
sut = APIClient()
mockURLSession = MockURLSession(data: nil, urlResponse: nil, error: nil)
sut.session = mockURLSession
}
func test_Execute_UsesCorrectHost() {
guard let request = createURLObject("https://foo.bar.com") else { XCTFail("Could not create URL object"); return }
let completion = { (Result<String>) in }
sut.call(with: request, completion: completion)
XCTAssertEqual(mockURLSession?.urlComponents?.host, "foo.bar")
}
}
extension APIClientTests {
class MockURLSession: SessionProtocol {
var url: URL?
private let dataTask: MockTask
var urlComponents: URLComponents? {
guard let url = url else { return nil }
return URLComponents(url: url, resolvingAgainstBaseURL: true)
}
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
dataTask = MockTask(data: data, urlResponse: urlResponse, error: error)
}
func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
self.url = url
dataTask.completionHandler = completionHandler
return dataTask
}
}
class MockTask: URLSessionDataTask {
private let data: Data?
private let urlResponse: URLResponse?
private let responseError: Error?
typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
var completionHandler: CompletionHandler?
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
self.data = data
self.urlResponse = urlResponse
responseError = error
}
override func resume() {
DispatchQueue.main.async { [weak self] in
self?.completionHandler?(self?.data, self?.urlResponse, self?.responseError)
}
}
}
func createURLObject(_ url: String) -> URLRequest? {
guard let url = URL(string: url) else { return nil }
return URLRequest(url: url)
}
}
Код, который я пытаюсь проверить, выглядит следующим образом:
import Foundation
enum Result<T> {
case success(T)
case failure(String)
}
protocol SessionProtocol {
func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?)-> Void) -> URLSessionDataTask
}
protocol APIClientProtocol {
var session: SessionProtocol { mutating get }
func call<T: Codable>(with request: URLRequest, completion: @escaping (Result<T>) -> Void) -> Void
}
struct APIClient: APIClientProtocol {
lazy var session: SessionProtocol = URLSession.shared
func call<T: Codable>(with request: URLRequest, completion: @escaping (Result<T>) -> Void) -> Void { }
}
extension URLSession: SessionProtocol { }
Вместо этого в этой строке:
let completion = { (Result<String>) in }
Я получаю следующие ошибки:
Невозможно определить тип возвращаемого значения сложного замыкания;добавить явный тип для устранения неоднозначности Ожидаемое имя параметра, за которым следует ':'