简体   繁体   中英

Cannot call value of non-function type 'URLSession' error with mockURLSession

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

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

Cannot call value of non-function type '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?

Edit___

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
    }

The signature of the delegate method is

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

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

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."

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM