测试NSURLSession“无法将简历发送到类NSURLSessionDataTask的抽象实例”

时间:2019-02-22 07:20:57

标签: swift testing mocking urlsession nsurlsessiondatatask

我想测试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 :(得分:1)

HERE,有人重写了这篇文章,您可以在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()