Browse Questions
Answer:
Use a custom URLProtocol subclass that intercepts URLSession requests and returns fake responses — no network needed, tests run instantly.
Code Example:
class MockURLProtocol: URLProtocol {
static var mockData: Data = Data()
static var mockStatusCode: Int = 200
override class func canInit(with request: URLRequest) -> Bool { true }
override class func canonicalRequest(for request: URLRequest) -> URLRequest { request }
override func startLoading() {
let response = HTTPURLResponse(
url: request.url!,
statusCode: MockURLProtocol.mockStatusCode,
httpVersion: nil,
headerFields: nil
)!
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
client?.urlProtocol(self, didLoad: MockURLProtocol.mockData)
client?.urlProtocolDidFinishLoading(self)
}
override func stopLoading() {}
}
// In test setup
let config = URLSessionConfiguration.ephemeral
config.protocolClasses = [MockURLProtocol.self]
let session = URLSession(configuration: config)
// Inject into service
MockURLProtocol.mockData = try! JSONEncoder().encode([Article.mock()])
let service = ArticleService(session: session)
let articles = try await service.fetchArticles()
XCTAssertEqual(articles.count, 1)