У меня есть сетевой уровень, работающий с генериками, и я использую протоколы, чтобы проверить его позже.Я следовал этому уроку https://medium.com/thecocoapps/network-layer-in-swift-4-0-972bf2ea5033
Это мой макет для тестирования:
import Foundation
@testable import TraktTest
class MockUrlSessionProvider: ProviderProtocol {
enum Mode {
case success
case empty
case fail
}
private var mode: Mode
init(mode: Mode) {
self.mode = mode
}
func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping (NetworkResponse<T>) -> Void) where T: Decodable {
switch mode {
case .success: completion(NetworkResponse.success(T))
case .empty: completion(.failure(.noData))
case .fail: completion(.failure(.unknown("Error")))
}
}
}
Я получаю сообщение об ошибке: Cannot convert value of type 'NetworkResponse<T.Type>' to expected argument type 'NetworkResponse<_>'
в этой строке: завершение (NetworkResponse.success (T))
Если я отправлю это для успешного завершения, он скомпилирует: try? JSONDecoder().decode(T.self, from: data!)
(фиктивные данные, которые я создал, используя encode и мою модель), но вылетает при достижении моей модели, потому что равен нулю, несмотря на то, что я закодировалиспользование JSONEncoder () с правильной моделью.
Я думаю, что это работает, потому что та же логика, которую я использую в своем классе, реализует ProviderProtocol в моем приложении:
final class URLSessionProvider: ProviderProtocol {
private var session: URLSessionProtocol
init(session: URLSessionProtocol = URLSession.shared) {
self.session = session
}
func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping (NetworkResponse<T>) -> Void) where T: Decodable {
let request = URLRequest(service: service)
session.dataTask(request: request) { [weak self] data, response, error in
let httpResponse = response as? HTTPURLResponse
self?.handleDataResponse(data: data, response: httpResponse, error: error, completion: completion)
}.resume()
}
private func handleDataResponse<T: Decodable>(data: Data?, response: HTTPURLResponse?, error: Error?, completion: (NetworkResponse<T>) -> Void) {
guard error == nil else { return completion(.failure(.unknown(error?.localizedDescription ?? "Error"))) }
guard let response = response else { return completion(.failure(.unknown("no_response".localized()))) }
switch response.statusCode {
case 200...299:
guard let data = data, let model = try? JSONDecoder().decode(T.self, from: data) else { return completion(.failure(.noData)) }
completion(.success(model))
default: completion(.failure(.unknown("no_response".localized())))
}
}
}
URLSessionProtocol простопротокол с методом dataTask, аналогичным методу URLSession.shared (получает URLRequest и возвращает данные, ответ и ошибку в завершении).
Ответы моей сети представляют собой пару перечислений:
enum NetworkResponse<T> {
case success(T)
case failure(NetworkError)
}
enum NetworkError {
case unknown(String)
case noData
}
В моем протоколе провайдера есть функция для выполнения запроса с использованием универсальных шаблонов:
protocol ProviderProtocol {
func request<T>(type: T.Type, service: ServiceProtocol, completion: @escaping(NetworkResponse<T>) -> Void) where T: Decodable
}
Я не думаю, что мне нужно использовать ServiceProtocol в моем тесте, потому что это настройка запроса с помощьюh конечная точка, заголовки, тело, идентификатор и т. д. Но это протокол, который я создал:
typealias Headers = [String: String]
typealias Parameters = [String: Any]
protocol ServiceProtocol {
func baseURL() -> URL
var path: String? { get }
var id: String? { get }
var method: HTTPMethod { get }
var task: Task { get }
var headers: Headers? { get }
var parametersEncoding: ParametersEncoding { get }
}
enum HTTPMethod: String {
case get = "GET"
case post = "POST"
}
enum Task {
case requestPlain
case requestParameters(Parameters)
}
enum ParametersEncoding {
case url
case json
}
В моем приложении у меня есть класс, который реализует ProviderProtocol и использует URLSession.shared для выполнения dataTask, когданекоторые viewModel вызывают запрос с подходящей моделью.
Я использую для тестирования с протоколами и конкретной моделью, но с обобщениями показывает мне эту ошибку.Как мне добиться, чтобы фиктивный провайдер использовал дженерики, чтобы я мог протестировать любую модель представления, которая делает вызов в сеть, используя разные типы моделей (заглушки).