gpt4 book ai didi

ios - 模拟 API 测试的 URLSession 是将无法识别的选择器发送到实例

转载 作者:行者123 更新时间:2023-11-28 11:32:27 26 4
gpt4 key购买 nike

我想在不调用服务器的情况下测试 API,因此我模拟了 URLSession 和 URLSessionDataTask,以便我可以将其注入(inject)到我的 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] : failed: caught "NSInvalidArgumentException", "-[MyAppTests.MockTask error]: unrecognized selector sent to instance 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 协议(protocol)扩展

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()
}
}

非常感谢您的帮助。

最佳答案

您没有覆盖 MockURLSession 中的方法 dataTask(with:completionHandler:)。于是,调用了原来的URLSessiondataTask(with:completionHandler:),内部调用了dataTaskForRequest:completion:

如果您成功覆盖了父类中的现有方法,Swift 编译器会声明为 override 关键字添加前缀。

将嵌套的 dataTask(with:completionHandler:) 移出 init(data:urlResponse:error:)

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
}

对于编辑的部分...

error 属性的继承似乎没有正常工作。 (这可能是 Swift 编译器的一个错误,与桥接 NSErrorError 有关。)

请试试这个:

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

private let _error: Error?
override var error: Error? {
return _error
}

var completionHandler: ((Data?, URLResponse?, Error?) -> Void)!

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

override func resume() {
DispatchQueue.main.async {
self.completionHandler(self.data, self.urlResponse, self.error)
}
}
}

关于ios - 模拟 API 测试的 URLSession 是将无法识别的选择器发送到实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56419151/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com