本文介绍了无法使用模拟URL会话调用非函数类型"URLSession"的值错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对带有模拟数据的URLSession委托进行单元测试.这是正在测试的委托函数:

I'm trying to unit test URLSession delegates with mockData. This is the delegate function that is being tested:

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

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

This is the unit test so far:

 func test_urlSession(){

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

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

每当我尝试将模拟URL会话作为参数注入时,都会出现错误:

Whenever I try to inject the mockURLSession as a parameter the error:

我正在测试响应(即404、200),这就是为什么要向模拟URL会话注入模拟响应的原因.关于如何将模拟UrlSession注入到委托中的任何想法?

I'm testing for responses (ie 404, 200) that's why I'm injecting the mockURLSession with mocked responses. Any idea on how to inject the mockUrlSession into the delegate?

编辑___

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
    }

推荐答案

委托方法的签名是

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

因此,第一个参数session必须为URLSession类型.

So the first argument, session, must be of type URLSession.

当您可以控制函数的签名时,您可以说:让我们不要使用URLSession.让我们使用URLSessionProtocol.然后我们可以替换符合该协议的任何类型."

When you can control the signature of a function, then you can say, "Let's not use URLSession. Let's use URLSessionProtocol instead. Then we can substitute any type that conforms to that protocol."

但是,在这种情况下并非如此.它必须是一个URLSession.

But that's not the true for this case. It has to be an URLSession.

解决方法是使用部分模拟.进行一个继承自URLSession的双重测试.我会说更改MockURLSession的基类",但是我不知道您是否在其他测试中使用它.您可能想要创建一个新的测试double来测试委托方法.

The workaround is to use partial mocking. Make a test double that inherits from URLSession. I would say, "Change MockURLSession's base class," but I don't know if you're using it in other tests. You may want to create a new test double to test the delegate method.

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

For more on partial mocking, see https://qualitycoding.org/swift-partial-mock/

这篇关于无法使用模拟URL会话调用非函数类型"URLSession"的值错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 17:05