The project demonstrates how to code generate Swift mocks using Sourcery.
Annotate the protocol you want to mock:
//sourcery: AutoMockable
protocol HTTPClient {
func execute(
request: URLRequest,
completion: @escaping (Result<Data, Error>) -> Void
)
}
Then build your Xcode project test target. During the build phase, Sourcery will generate HTTPClient+AutoMockable.generated.swift
that is ready for use in your tests.
Given CurrenciesAPIService
that we want to test:
final class CurrenciesAPIService {
private let httpClient: HTTPClient
init(httpClient: HTTPClient) {
self.httpClient = httpClient
}
func allCurrencies(completion: @escaping (Result<[CurrencyDTO], Error>) -> Void) {
httpClient.execute(request: .allCurrencies()) { result in
completion(
result.flatMap { data in Result { try JSONDecoder().decode([CurrencyDTO].self, from: data) }}
)
}
}
}
And a generated HTTPClientMock
:
// Generated using Sourcery 1.3.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all
import UIKit
@testable import AutoMockable
class HTTPClientMock: HTTPClient {
//MARK: - execute
var executeRequestCompletionCallsCount = 0
var executeRequestCompletionCalled: Bool {
return executeRequestCompletionCallsCount > 0
}
var executeRequestCompletionReceivedArguments: (request: URLRequest, completion: (Result<Data, Error>) -> Void)?
var executeRequestCompletionReceivedInvocations: [(request: URLRequest, completion: (Result<Data, Error>) -> Void)] = []
var executeRequestCompletionClosure: ((URLRequest, @escaping (Result<Data, Error>) -> Void) -> Void)?
func execute(request: URLRequest, completion: @escaping (Result<Data, Error>) -> Void) {
executeRequestCompletionCallsCount += 1
executeRequestCompletionReceivedArguments = (request: request, completion: completion)
executeRequestCompletionReceivedInvocations.append((request: request, completion: completion))
executeRequestCompletionClosure?(request, completion)
}
}
The next test verifies that CurrenciesAPIService
correctly handles malformed data in response:
import Foundation
import XCTest
@testable import AutoMockable
class CurrenciesAPIServiceTests: XCTestCase {
let httpClient = HTTPClientMock()
lazy var sut = CurrenciesAPIService(httpClient: httpClient)
func test_allCurrencies_withMalformedData_returnsError() throws {
httpClient.executeRequestCompletionClosure = { _, completion in
completion(.success(Data())) // <--- Stub malformed data
}
var result: Result<[CurrencyDTO], Error>?
sut.allCurrencies { result = $0 }
XCTAssertThrowsError(try result?.get())
}
}
Verify CurrenciesAPIService
correctly parses a response with valid payload:
class CurrenciesAPIServiceTests: XCTestCase {
...
func test_allCurrencies_withResponseSuccess_returnsValidData() throws {
let expected = CurrencyDTO(
currencyCode: "A",
country: "B",
currencyName: "C",
countryCode: "D"
)
let data = try JSONEncoder().encode([expected])
httpClient.executeRequestCompletionClosure = { _, completion in
completion(.success(data)) // <--- Stub valid data
}
var result: Result<[CurrencyDTO], Error>?
sut.allCurrencies { result = $0 }
XCTAssertEqual(try result?.get(), [expected])
}
}