无法调用非功能类型的值' URLSession' mockURLSession

时间:2018-04-16 21:50:13

标签: ios swift mocking nsurlsession xctest

我尝试使用mockData对URLSession委托进行单元测试。这是正在测试的委托函数:

urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 

到目前为止,这是单元测试:

 func test_urlSession(){

     let mockSession = MockURLSession(mockResponse: MockURLSession().successHttpURLResponse(request: self.urlRequest!) as! HTTPURLResponse)

                    //error here
    sut?.urlSession(mockSession, task: MockURLSessionDataTask, didCompleteWithError: Error)
}

每当我尝试将mockURLSession作为参数注入错误:

  

无法调用非功能类型的值' URLSession'

我正在测试响应(即404,200),这就是为什么我用模拟响应注入mockURLSession的原因。有关如何将mockUrlSession注入委托的任何想法吗?

编辑___

protocol URLSessionDataTaskProtocol {
    func resume()
}

protocol URLSessionProtocol {
    typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void

    func dataTask(with request: Request, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol{
    func dataTask(with request: Request, completionHandler: @escaping URLSessionProtocol.DataTaskResult) -> URLSessionDataTaskProtocol {
        let task:URLSessionDataTask = dataTask(with: request, completionHandler: {
            (data:Data?, response:URLResponse?, error:Error?) in completionHandler(data,response,error) }) as! URLSessionDataTask;
        return task as URLSessionDataTaskProtocol
    }
}

extension URLSessionDataTask: URLSessionDataTaskProtocol {}


class MockURLSession: URLSessionProtocol {

    typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
    var nextDataTask = MockURLSessionDataTask()
    var nextData: Data?
    var nextError: Error?
    private (set) var lastURL: URL?
    private var mockResponse: HTTPURLResponse?

    init() { }
    init(mockResponse: HTTPURLResponse) {
        self.mockResponse = mockResponse
    }

    func successHttpURLResponse(request: Request) -> URLResponse {
        return HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
    }

    func wrongHttpURLResponse(request: Request, statusCode:Int) -> URLResponse {
        return HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "HTTP/1.1", headerFields: nil)!
    }

    func dataTask(with request: Request, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
        lastURL = request.url
        nextDataTask.resume()
        if let mockResponse = mockResponse {
            completionHandler(nextData, mockResponse, nextError)
        }
        else {
            //default case is success
            completionHandler(nextData, successHttpURLResponse(request: request), nextError)
        }

        return nextDataTask
    }

}

class MockURLSessionDataTask: URLSessionDataTaskProtocol {
    private (set) var resumeWasCalled = false

    func resume() {
        resumeWasCalled = true
    }

1 个答案:

答案 0 :(得分:0)

委托方法的签名是

urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 

因此第一个参数session必须是URLSession类型。

当你可以控制一个函数的签名时,你可以说,“我们不要使用URLSession。让我们使用URLSessionProtocol。然后我们可以替换任何符合该协议的类型。”

但对于这种情况,情况并非如此。它必须是一个URLSession。

解决方法是使用部分模拟。创建一个继承自URLSession的测试double。我会说,“改变MockURLSession的基类,”但我不知道你是否在其他测试中使用它。您可能想要创建一个新的测试双精度来测试委托方法。

有关部分模拟的更多信息,请参阅https://qualitycoding.org/swift-partial-mock/