Как смоделировать структуру URL? - PullRequest
0 голосов
/ 23 марта 2019

Я пишу некоторый код, чтобы облегчить тестирование.После исследования я обнаружил, что хороший способ сделать URLSession тестируемым - это привести его в соответствие с протоколом и использовать этот протокол в классе, который мне нужно протестировать.Я применил тот же метод к URL.Однако теперь мне нужно уменьшить параметр url как тип URL.Это кажется немного "опасным" для меня.Как правильно сделать URL тестируемым?Как я могу также высмеять тип URLSessionDataTask, возвращаемый dataTask?

import Foundation

protocol URLSessionForApiRequest {
    func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
}

protocol URLForApiRequest {
    init?(string: String)
}

extension URLSession: URLSessionForApiRequest {}

extension URL: URLForApiRequest {}

class ApiRequest {
    class func makeRequest(url: URLForApiRequest, urlSession: URLSessionForApiRequest) {
        guard let url = url as? URL else { return }
        let task = urlSession.dataTask(with: url) { _, _, _ in print("DONE") }
        task.resume()
    }

}

1 Ответ

0 голосов
/ 23 марта 2019

Вы хотите создать протокол, который обернет функцию, которую вы собираетесь вызывать, затем создать конкретную реализацию и макетную реализацию, которая возвращает то, с чем вы инициализируете ее. Вот пример:

import UIKit
import PlaygroundSupport

protocol RequestProvider {
    func request(from: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void)
}

class ApiRequest: RequestProvider {
    func request(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) {
        URLSession.shared.dataTask(with: url, completionHandler: completion).resume
    }
}

class MockApiRequest: RequestProvider {
    enum Response {
        case value(Data, URLResponse), error(Error)
    }
    private let response: Response
    init(response: Response) {
        self.response = response
    }
    func request(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) {
        switch response {
        case .value(let data, let response):
            completion(data, response, nil)
        case .error(let error):
            completion(nil, nil, error)
        }
    }
}

class SomeClassThatMakesAnAPIRequest {
    private let requestProvider: RequestProvider
    init(requestProvider: RequestProvider) {
        self.requestProvider = requestProvider
    }
    //Use the requestProvider here and it uses either the Mock or the "real" API provider based don what you injected
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...