Как заглушить URLSession в Swift?

Я следовал этому уроку, чтобы заглушить URLSession, Пример был сделан путем создания протокола и расширения существующих URLSession,

protocol URLSessionProtocol {
    typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
    func dataTask(with request: NSURLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
    func dataTask(with request: NSURLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
        return dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTaskProtocol
    }
}

Модульные тесты работают как положено. Но когда я пытаюсь запустить реальную вещь, URLSession -> datatask() попадает в бесконечный цикл и вылетает. Похоже, что datatask () вызывает себя.

Что я пропускаю, пожалуйста?

ОБНОВИТЬ:

protocol URLSessionDataTaskProtocol {
    var originalRequest: URLRequest? { get }
    func resume()
}

extension URLSessionDataTask: URLSessionDataTaskProtocol {}

1 ответ

Решение

Я наконец нашел решение. Это восхитительно, так как мы скучали по дереву за деревьями. Есть две проблемы:

1) Кажется, что Swift 4 изменил подпись для dataTask(with: NSURLRequest) в dataTask(with: URLRequest)

Поэтому строка в моем первом вопросе будет соответствовать только сигнатуре протокола, и она никогда не попадет в dataTask внутри URLSessionотсюда и бесконечный цикл. Чтобы решить эту проблему, мне пришлось изменить NSURLRequest в URLRequest и рефакторинг кода соответственно.

2) подпись остается расплывчатой, поэтому лучше сначала сохранить результат как dataTask с приведением к URLSessionDataTask а затем вернуть переменную.

Новый переработанный код для Swift 4:

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

protocol URLSessionProtocol {
    func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}

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

Я также обнаружил, что должен был сделать инъекцию URLSession.shared как одиночка, а не как URLSession()в противном случае это может привести к сбою.

Пришел сюда понять, как издеваться URLSession такие задачи как URLSessionDataTask?

Примерно Swift 5, гораздо проще издеваться надURLProtocol который URLSession используется для отправки запроса.

См. Раздел Unit Testing URLSession using URLProtocol.

Другие вопросы по тегам