Тестирование NSURLSession "не может быть отправлено резюме в абстрактный экземпляр класса NSURLSessionDataTask" - PullRequest
0 голосов
/ 22 февраля 2019

Я хочу протестировать NSURLSession, но получаю ошибку «Невозможно отправить резюме в абстрактный экземпляр класса NSURLSessionDataTask».

Пример кода в https://github.com/stevencurtis/abstract-instanceofclassNSURLSessionDataTask

Мой HTTP-менеджер работает нормально:

class HTTPManager {

    static let shared: HTTPManager = HTTPManager()

    private let session: URLSessionProtocol

    init(session: URLSessionProtocol = URLSession.shared) {
        self.session = session

    }

    public func get(urlString: String, completionBlock: ((Data?) -> Void)?) {

        let url = URL(string: urlString)
        if let usableUrl = url {
            let request = URLRequest(url: usableUrl)
            let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
                (completionBlock?(data))!
            })
            task.resume()
        }
    }

}

Однако я пытаюсь смоделировать это

class MockURLSession: URLSessionProtocol {
    func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        return URLSessionDataTask()
    }
    var searchedURL = URL(string: "asd")
}

И затем создать тест:

func testGetRequest() {
    let url = URL(string: "url")
    let session = MockURLSession()
    let sub = HTTPManager(session: session)


    sub.get(urlString: "url", completionBlock: { [weak self] (data: Data?) -> Void in
        print ("vc")
        }
    )
}

Ошибки тестов с: резюме не может быть отправлено наабстрактный экземпляр класса NSURLSessionDataTask ", и я не могу придумать способ обойти эту ошибку!

1 Ответ

0 голосов
/ 22 февраля 2019

ЗДЕСЬ кто-то переписал статью, и вы можете проверить приведенный ниже код в Playground:

import UIKit
import XCTest
import PlaygroundSupport
import Foundation

// Protocol for MOCK/Real
protocol URLSessionProtocol {
    typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void

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

protocol URLSessionDataTaskProtocol {
    func resume()
}

//MARK: HttpClient Implementation
class HttpClient {

    typealias completeClosure = ( _ data: Data?, _ error: Error?)->Void

    private let session: URLSessionProtocol

    init(session: URLSessionProtocol) {
        self.session = session

    }

    func get( url: URL, callback: @escaping completeClosure ) {
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        let task = session.dataTask(with: request) { (data, response, error) in
            callback(data, error)
        }
        task.resume()
    }

}

//MARK: Conform the protocol
extension URLSession: URLSessionProtocol {
    func dataTask(with request: URLRequest, completionHandler: @escaping URLSessionProtocol.DataTaskResult) -> URLSessionDataTaskProtocol {
        return dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTask
    }
}

extension URLSessionDataTask: URLSessionDataTaskProtocol {}

//MARK: MOCK
class MockURLSession: URLSessionProtocol {

    var nextDataTask = MockURLSessionDataTask()
    var nextData: Data?
    var nextError: Error?

    private (set) var lastURL: URL?

    func successHttpURLResponse(request: URLRequest) -> URLResponse {
        return HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
    }

    func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
        lastURL = request.url

        completionHandler(nextData, successHttpURLResponse(request: request), nextError)
        return nextDataTask
    }

}

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

    func resume() {
        resumeWasCalled = true
    }
}

//MARK: Test
class HttpClientTests: XCTestCase {

    var httpClient: HttpClient!
    let session = MockURLSession()

    override func setUp() {
        super.setUp()
        httpClient = HttpClient(session: session)
    }

    override func tearDown() {
        super.tearDown()
    }

    func test_get_request_with_URL() {

        guard let url = URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json") else {
            fatalError("URL can't be empty")
        }

        httpClient.get(url: url) { (success, response) in
            // Return data
        }

        XCTAssert(session.lastURL == url)

    }

    func test_get_resume_called() {

        let dataTask = MockURLSessionDataTask()
        session.nextDataTask = dataTask

        guard let url = URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json") else {
            fatalError("URL can't be empty")
        }

        httpClient.get(url: url) { (success, response) in
            // Return data
        }

        XCTAssert(dataTask.resumeWasCalled)
    }

    func test_get_should_return_data() {
        let expectedData = "{}".data(using: .utf8)

        session.nextData = expectedData

        var actualData: Data?
        httpClient.get(url: URL(string: "http://gojek-contacts-app.herokuapp.com/contacts.json")!) { (data, error) in
            actualData = data
        }

        XCTAssertNotNil(actualData)
    }

}

HttpClientTests.defaultTestSuite.run()
...