G. *_*arc 5 unit-testing swift combine
我正在尝试使用 URLSession.DataTaskPublisher 为我的 API 编写一些单元测试。我在 Stackoverflow 上发现了一个已经存在的问题,但我正在努力使用建议的解决方案来实现一个工作班级。
这是现有的问题:如何模拟 URLSession.DataTaskPublisher
protocol APIDataTaskPublisher {
func dataTaskPublisher(for request: URLRequest) -> URLSession.DataTaskPublisher
}
class APISessionDataTaskPublisher: APIDataTaskPublisher {
func dataTaskPublisher(for request: URLRequest) -> URLSession.DataTaskPublisher {
return session.dataTaskPublisher(for: request)
}
var session: URLSession
init(session: URLSession = URLSession.shared) {
self.session = session
}
}
class URLSessionMock: APIDataTaskPublisher {
func dataTaskPublisher(for request: URLRequest) -> URLSession.DataTaskPublisher {
// How can I return a mocked URLSession.DataTaskPublisher here?
}
}
Run Code Online (Sandbox Code Playgroud)
我的 API 然后像这样使用上面的:
class MyAPI {
/// Shared URL session
private let urlSession: APIDataTaskPublisher
init(urlSession: APIDataTaskPublisher = APISessionDataTaskPublisher(session: URLSession.shared)) {
self.urlSession = urlSession
}
}
Run Code Online (Sandbox Code Playgroud)
我不知道的是如何实现 URLSessionMock.dataTaskPublisher()。
rob*_*off 15
不模拟可能会更简单DataTaskPublisher。你真的关心出版商是否是DataTaskPublisher? 可能不是。什么你可能关心的是得到同样Output和Failure类型的DataTaskPublisher。因此,将您的 API 更改为仅指定:
protocol APIProvider {
typealias APIResponse = URLSession.DataTaskPublisher.Output
func apiResponse(for request: URLRequest) -> AnyPublisher<APIResponse, URLError>
}
Run Code Online (Sandbox Code Playgroud)
符合URLSession它的生产用途:
extension URLSession: APIProvider {
func apiResponse(for request: URLRequest) -> AnyPublisher<APIResponse, URLError> {
return dataTaskPublisher(for: request).eraseToAnyPublisher()
}
}
Run Code Online (Sandbox Code Playgroud)
然后您的模拟可以以任何方便的方式创建发布者。例如:
struct MockAPIProvider: APIProvider {
func apiResponse(for request: URLRequest) -> AnyPublisher<APIResponse, URLError> {
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
let data = "Hello, world!".data(using: .utf8)!
return Just((data: data, response: response))
.setFailureType(to: URLError.self)
.eraseToAnyPublisher()
}
}
Run Code Online (Sandbox Code Playgroud)
如果您将要测试的每个 API 调用存储在 UT 捆绑存根 JSON(XML 或其他内容)中,那么最简单的模拟代码可能如下所示
class URLSessionMock: APIDataTaskPublisher {
func dataTaskPublisher(for request: URLRequest) -> URLSession.DataTaskPublisher {
// here might be created a map of API URLs to cached stub replies
let stubReply = request.url?.lastPathComponent ?? "stub_error"
return URLSession.shared.dataTaskPublisher(for: Bundle(for: type(of: self)).url(forResource: stubReply, withExtension: "json")!)
}
}
Run Code Online (Sandbox Code Playgroud)
因此,请改为调用网络服务器,您的发布者是使用具有已知数据的本地存储资源的 URL 创建的,因此您可以验证所有工作流程。