【问题标题】:Test URLSession Delegates with mock data使用模拟数据测试 URLSession 委托
【发布时间】:2018-04-13 09:49:40
【问题描述】:

我们有 2 个 URLSession 委托在其正文中使用自定义代码(未显示以使这篇文章更清晰):

   public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {}

  public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
     if let error = error {
            //code here
        } else if let response = task.response as? HTTPURLResponse, var dataResponse = self.dataReceived {
            if (400...499).contains(response.statusCode) {
                //handle response here
            }
}

我们有一个 mockURLSession 类:

protocol URLSessionDataTaskProtocol {
    func resume()
}

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

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

class MockURLSession: URLSessionProtocol {

    typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
    var nextDataTask = MockURLSessionDataTask()
    var nextData: Data?
    var nextError: Error?

    private (set) var lastURL: URL?

    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()
        completionHandler(nextData, successHttpURLResponse(request: request), nextError)
        return nextDataTask
    }

}

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

    func resume() {
        resumeWasCalled = true
    }
}

我们遇到的问题是我必须为来自模拟服务器的特定响应(例如 404)编写单元测试。通常我会这样写响应:

  let urlReponse = MockURLSession().wrongHttpURLResponse(request: self.urlRequest!, statusCode: 404)

我遇到的问题是,因为我们使用的是 URLSession 委托,所以我无法将 mockResponse 作为参数注入到函数中,除非它不会被调用。基于模拟响应测试 URLSession 委托的最佳方法是什么?

【问题讨论】:

  • 如果只想测试delegate,可以直接在你的测试用例中调用

标签: ios swift unit-testing urlsession


【解决方案1】:

您可以在初始化MockURLSession 时注入模拟响应。

将以下内容添加到您的MockURLSession

private var mockResponse: HTTPURLResponse?

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

修改模拟的dataTask 函数以使用模拟响应调用完成处理程序(如果您提供了它):

if let mockResponse = mockResponse {
    completionHandler(nextData, mockResponse, nextError)
}
else {
    //default case is success
    completionHandler(nextData, successHttpURLResponse(request: request), nextError)
}

现在,当您想要测试错误响应时,请在创建模拟会话时注入它:

let mockResponse = HTTPURLResponse(url: self.urlRequest.url!, statusCode: 404, httpVersion: "HTTP/1.1", headerFields: nil)!
let mockURLSession = MockURLSession(mockResponse: mockResponse)

dataTask 被调用时,将使用你的模拟响应:

mockURLSession.dataTask(with: self.urlRequest) { (data, response, error) in
    if let response = response as? HTTPURLResponse {
        print("Status Code: \(response.statusCode)") // "Status Code: 404"
    }
}

【讨论】:

  • 这真是个好东西,非常感谢。但是当我尝试将 mockUrlSession 作为参数插入到 urlSession 委托中时:sut?.urlSession(mockURLSession, task:URLSessionTask, didCompleteWithError: Error?),它抱怨错误:/Users/justin/Code/EComAPI/EComAPI/EComAPITests /CoreTests/DownloadTests.swift:58:24:无法调用非函数类型'URLSession'的值
  • 那是因为你的方法需要 URLSession。您要么必须更改模拟以从 URLSession 继承,要么更改您的方法以接受 URLSessionProtocol。这无疑会带来其他变化,我现在无法研究。今天晚些时候我会试着看看。
  • 我认为用您的最新代码发布一个新问题以及您如何尝试调用它会有所帮助。我不确定你的 .urlSession 方法是用来做什么的。
  • 我在另一个帖子中更新了这个问题:stackoverflow.com/questions/49866777/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-24
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
  • 2010-10-05
相关资源
最近更新 更多