Я хочу протестировать API, не совершая серверный вызов, поэтому я имитирую URLSession и URLSessionDataTask, чтобы добавить его в мой класс API.
class MockURLSession: URLSession {
private let mockTask: MockTask
var cachedUrl: URL?
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
mockTask = MockTask(data: data, urlResponse: urlResponse, error:
error)
}
override func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
self.cachedUrl = url
mockTask.completionHandler = completionHandler
return mockTask
}
}
class MockTask: URLSessionDataTask {
private let data: Data?
private let urlResponse: URLResponse?
var completionHandler: ((Data?, URLResponse?, Error?) -> Void)!
init(data: Data?, urlResponse: URLResponse?, error: Error?) {
self.data = data
self.urlResponse = urlResponse
}
override func resume() {
DispatchQueue.main.async {
self.completionHandler(self.data, self.urlResponse, self.error)
}
}
}
Здесь, когда я запускаю этот тест, он проходит в моем классе API, вызывая метод getMovies. Экземпляр, который я получаю, - это своего рода MockURLSession, и это нормально. В следующий момент он выдает этот ApiTests testGetMoviesSuccessReturnsMovies]: не удалось: пойман "NSInvalidArgumentException", "- [MyAppTests.MockTask error]: нераспознанный селектор отправлен в экземпляр 0x600002010500
func testGetMoviesSuccessReturnsMovies() {
let jsonData = "[{\"title\": \"Spider Man Far From Home\",\"detail\": \"The first Spider-Man featuring Tom Holland in the iconic role\"}]".data(using: .utf8)
var mockURLSession = MockURLSession(data: jsonData, urlResponse: nil, error: nil)
let apiRespository = APIRepository(session: mockURLSession)
let moviesExpectation = expectation(description: "movies")
var moviesResponse: Result<[Movie]>?
apiRespository.getMovies { (movies) in
moviesResponse = movies
moviesExpectation.fulfill()
}
waitForExpectations(timeout: 10) { (error) in
XCTAssertNotNil(moviesResponse)
}
}
Вот мое расширение протокола для API
extension Gettable {
func get<T:Decodable>(with decodingType: T.Type, url: String, session: URLSession, completion:@escaping(Result<T>) -> Void) {
let dataTask = session.dataTask(with: URL(string: url)!) { (data, response, error) in
guard data != nil && error == nil else {
return
}
do {
let decoder = JSONDecoder()
let parsedObj = try decoder.decode(T.self, from: data ?? Data())
completion(Result.success(parsedObj))
}
catch let parsedError {
completion(Result.failure(parsedError))
}
}
dataTask.resume()
}
}
Ваша помощь будет высоко оценена.