Created
April 12, 2021 10:33
-
-
Save bocato/12d606ca0339bb58b1c4c9daaf50fd11 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
protocol MockURLResponder { | |
static func respond(to request: URLRequest) throws -> Data | |
static func response(for request: URLRequest) -> URLResponse | |
} | |
final class URLProtocolMock<Responder: MockURLResponder>: URLProtocol { | |
override class func canInit(with request: URLRequest) -> Bool { | |
return true | |
} | |
override class func canonicalRequest(for request: URLRequest) -> URLRequest { | |
return request | |
} | |
override func startLoading() { | |
guard let client = client else { return } | |
let response = Responder.response(for: request) | |
client.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) | |
do { | |
let data = try Responder.respond(to: request) | |
client.urlProtocol(self, didLoad: data) | |
} catch { | |
client.urlProtocol(self, didFailWithError: error) | |
} | |
client.urlProtocolDidFinishLoading(self) | |
} | |
override func stopLoading() { | |
// Do nothing. | |
} | |
} | |
enum MockURLResponderStub: MockURLResponder { | |
static var resultToBeReturned: Result<Data, Error> = .success(.init()) | |
static func respond(to request: URLRequest) throws -> Data { try resultToBeReturned.get() } | |
static var responseToBeReturned: URLResponse = .init() | |
static func response(for request: URLRequest) -> URLResponse { responseToBeReturned } | |
} | |
extension URLSession { | |
convenience init<T: MockURLResponder>(mockResponder: T.Type) { | |
let mockSessionConfiguration = URLSessionConfiguration.ephemeral | |
mockSessionConfiguration.protocolClasses = [URLProtocolMock<T>.self] | |
self.init(configuration: mockSessionConfiguration) | |
URLProtocol.registerClass(URLProtocolMock<T>.self) | |
} | |
static func mocking( | |
response: URLResponse = .init(), | |
result: Result<Data, Error> = .success(.init()) | |
) -> URLSession { | |
MockURLResponderStub.responseToBeReturned = response | |
MockURLResponderStub.resultToBeReturned = result | |
return .init(mockResponder: MockURLResponderStub.self) | |
} | |
} | |
import XCTest | |
enum FailingMockURLResponder: MockURLResponder { | |
static var file: StaticString = #file | |
static var line: UInt = #line | |
static func respond(to request: URLRequest) throws -> Data { | |
XCTFail("MockURLResponder.respond(to:) should not be called on this test.", file: file, line: line) | |
return .init() | |
} | |
static func response(for request: URLRequest) -> URLResponse { | |
XCTFail("MockURLResponder.response(for:) should not be called on this test.", file: file, line: line) | |
return .init() | |
} | |
} | |
extension URLSession { | |
static func failing( | |
file: StaticString = #file, | |
line: UInt = #line | |
) -> URLSession { | |
FailingMockURLResponder.file = file | |
FailingMockURLResponder.line = line | |
return .init(mockResponder: FailingMockURLResponder.self) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment