Swift 无法转换类型为';髓鞘<;T.Type>';到预期的参数类型';髓鞘<_&燃气轮机';

Swift 无法转换类型为';髓鞘<;T.Type>';到预期的参数类型';髓鞘<_&燃气轮机';,swift,unit-testing,generics,Swift,Unit Testing,Generics,我有一个处理泛型的网络层,我正在使用协议,以便稍后进行测试。我遵循了这个教程 这是我的模拟测试: import Foundation @testable import TraktTest class MockUrlSessionProvider: ProviderProtocol { enum Mode { case success case empty case fail } private var mode: Mo

我有一个处理泛型的网络层,我正在使用协议,以便稍后进行测试。我遵循了这个教程

这是我的模拟测试:

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")))
        }

    }
}
URLSessionProtocol只是一个协议,其方法dataTask与URLSession.shared中的方法dataTask相同(接收URLRequest并在完成时返回数据、响应和错误)

我的网络响应是几个枚举:

enum NetworkResponse<T> {
    case success(T)
    case failure(NetworkError)
}

enum NetworkError {
    case unknown(String)
    case noData
}
在我的应用程序中,我有一个实现ProviderProtocol的类,当某个viewModel使用适当的模型调用请求时,我使用URLSession.shared来生成dataTask


我习惯于使用协议和特定模型进行测试,但泛型向我展示了这个错误。如何实现使用泛型的模拟提供程序,以便测试使用不同类型的模型(存根)调用网络的任何viewModel。

发生错误的原因是
NetworkResponse
需要
T
的实例,而模拟试图提供实际的
T

因此,您需要以某种方式提供一个实例,但是这不能由mock生成,因为它没有关于如何构造实例的足够信息

我建议在创建模拟时,从外部注入成功价值。您可以通过使mock类成为泛型,或者使
模式成为
枚举泛型来实现这一点。下面是后者的示例实现:

class MockUrlSessionProvider:ProviderProtocol{
//使枚举通用,以支持注入成功值
枚举模式{
成功案例(T)
空箱
案例失败
}
//需要将其作为'Any'来覆盖所有可能的T泛型参数
私有var模式:任意
//但是,初始值设定项可以非常具体
初始化(模式:模式){
self.mode=mode
}
func请求(类型:T.type,服务:ServiceProtocol,完成:@escaping(NetworkResponse)->Void),其中T:Decodable{
//如果未正确配置模拟,则不执行任何操作
guard let mode=模式as?模式else{return}
//或者强制转换并使单元测试崩溃,这将有助于捕获早期配置问题
//让mode=modeas!mode
开关模式{
案例let.success(value):完成(NetworkResponse.success(value))
case.empty:完成(.failure(.noData))
case.fail:完成(.failure(.unknown(“Error”))
}
}
}

如何定义
服务协议
网络响应
提供者协议
?你能用这些信息更新这个问题,使它更接近a吗?一个选项是将
success(T)
的关联值更改为
success(T?
(假设定义与文章中的定义类似),然后你的完成将变成
completion(.success(someObject as?T))
用于(可解码)对象或
完成(.success(nil))
用于无值。@Cristik我用您询问的信息更新我的问题。我认为问题是在我的测试中错误地使用了泛型。@Alladinian我不知道使用nil是什么,因为在我的应用程序中,我必须检查模型是否不是nil,它不能是可选的。如果没有模型,这是一个失败的案例。非常感谢@Cristik!使用枚举注入模型完全有效!
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
}
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
}