如何正确模拟此完成处理程序进行测试

时间:2018-12-26 10:23:54

标签: swift unit-testing completionhandler xctestcase

我想针对我的网络代码编写单元测试。

我想断言我的主机设置正确。

我的网络代码使用泛型,因此我可以基于调用的终点传入预期的响应模型。

我的XCTTestCase如下:

@testable import Home
import XCTest

class APIClientTests: XCTestCase {
    var sut: APIClient!
    var mockURLSession: MockURLSession!

    override func setUp() {
        sut = APIClient()
        mockURLSession = MockURLSession(data: nil, urlResponse: nil, error: nil)
        sut.session = mockURLSession
    }

    func test_Execute_UsesCorrectHost() {
        guard let request = createURLObject("https://foo.bar.com") else { XCTFail("Could not create URL object"); return }

        let completion = { (Result<String>) in }

        sut.call(with: request, completion: completion)

        XCTAssertEqual(mockURLSession?.urlComponents?.host, "foo.bar")
    }
}

extension APIClientTests {
    class MockURLSession: SessionProtocol {
        var url: URL?
        private let dataTask: MockTask
        var urlComponents: URLComponents? {
            guard let url = url else { return nil }
            return URLComponents(url: url, resolvingAgainstBaseURL: true)
        }

        init(data: Data?, urlResponse: URLResponse?, error: Error?) {
            dataTask = MockTask(data: data, urlResponse: urlResponse, error: error)
        }

        func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
            self.url = url
            dataTask.completionHandler = completionHandler
            return dataTask
        }
    }

    class MockTask: URLSessionDataTask {
        private let data: Data?
        private let urlResponse: URLResponse?
        private let responseError: Error?

        typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
        var completionHandler: CompletionHandler?

        init(data: Data?, urlResponse: URLResponse?, error: Error?) {
            self.data = data
            self.urlResponse = urlResponse
            responseError = error
        }

        override func resume() {
            DispatchQueue.main.async { [weak self] in
                self?.completionHandler?(self?.data, self?.urlResponse, self?.responseError)
            }
        }
    }

    func createURLObject(_ url: String) -> URLRequest? {
        guard let url = URL(string: url) else { return nil }
        return URLRequest(url: url)
    }
}

我要测试的代码如下

import Foundation

enum Result<T> {
    case success(T)
    case failure(String)
}

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

protocol APIClientProtocol {
    var session: SessionProtocol { mutating get }
    func call<T: Codable>(with request: URLRequest, completion: @escaping (Result<T>) -> Void) -> Void

}

struct APIClient: APIClientProtocol {

    lazy var session: SessionProtocol = URLSession.shared

    func call<T: Codable>(with request: URLRequest, completion: @escaping (Result<T>) -> Void) -> Void { }

}

extension URLSession: SessionProtocol { }

代替这一行:

let completion = { (Result<String>) in }

我遇到以下错误:

  

无法推断复杂的闭包返回类型;添加显式类型   消除期望参数名称的歧义,后跟':'

0 个答案:

没有答案