【问题标题】:Cannot call value of non-function type 'URLSession' error with mockURLSession无法使用 mockURLSession 调用非函数类型“URLSession”错误的值
【发布时间】:2023-03-03 15:26:01
【问题描述】:

我正在尝试使用 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
    }

【问题讨论】:

  • 最后一个参数传递nil,而不是Error
  • MockURLSession 是如何定义的?
  • @JonReid 我用 mockURLSession 更新了问题

标签: ios swift mocking nsurlsession xctest


【解决方案1】:

委托方法的签名是

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

所以第一个参数session 必须是 URLSession 类型。

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

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

解决方法是使用部分模拟。制作一个继承自 URLSession 的测试替身。我会说,“更改 MockURLSession 的基类”,但我不知道您是否在其他测试中使用它。您可能需要创建一个新的测试替身来测试委托方法。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-04
    • 1970-01-01
    • 2017-08-16
    • 2020-02-01
    • 2021-01-15
    • 2021-03-30
    相关资源
    最近更新 更多