[英]How to stub URLSession in Swift?
I have been following this tutorial to stub out URLSession
.我一直在关注本教程来删除
URLSession
。 The example was done by creating a protocol and extending the existing URLSession
. 该示例是通过创建协议并扩展现有
URLSession
。
protocol URLSessionProtocol {
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
func dataTask(with request: NSURLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}
extension URLSession: URLSessionProtocol {
func dataTask(with request: NSURLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTaskProtocol
}
}
The unit tests work as expected.单元测试按预期工作。 But when I try to run the real thing, the URLSession -> datatask() gets into an infinite loop and it crashes.
但是当我尝试运行真实的东西时, URLSession -> datatask() 进入无限循环并崩溃。 It seems to be that datatask() is calling itself.
似乎 datatask() 正在调用自己。
What am I overlooking, please?请问我在看什么?
UPDATE:更新:
protocol URLSessionDataTaskProtocol {
var originalRequest: URLRequest? { get }
func resume()
}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}
I have finally found the solution.我终于找到了解决方案。 It's fascinating as we missed the wood for the trees.
这很有趣,因为我们只见树木不见森林。 There are two issues:
有两个问题:
1) It seems that Swift 4 has changed the signature for dataTask(with: NSURLRequest)
to dataTask(with: URLRequest)
1) Swift 4 似乎已经将
dataTask(with: NSURLRequest)
的签名更改为dataTask(with: URLRequest)
Therefore the line in my opening question would only match to the Protocol's func signature, and it would never hit the dataTask
inside URLSession
, hence the infinite loop.因此,我的开头问题中的行只会与协议的 func 签名匹配,并且它永远不会命中
dataTask
URLSession
,因此是无限循环。 To solve this issue I had to change NSURLRequest
to URLRequest
and refactor the code accordingly.为了解决这个问题,我不得不将
NSURLRequest
更改为URLRequest
并相应地重构代码。
2) The signature remains vague, hence it is better to store the result as dataTask first with a cast to URLSessionDataTask
and then return the variable. 2) 签名仍然模糊,因此最好先将结果存储为
URLSessionDataTask
,然后转换为URLSessionDataTask
,然后返回变量。
New refactored Code for Swift 4: Swift 4 的新重构代码:
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol
}
extension URLSession: URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
let task:URLSessionDataTask = dataTask(with: request, completionHandler: {
(data:Data?, response:URLResponse?, error:Error?) in completionHandler(data,response,error) }) as URLSessionDataTask
return task
}
}
I also found I had to inject URLSession.shared
as a singleton and not as URLSession()
, otherwise it could crash.我还发现我必须将
URLSession.shared
作为单例而不是URLSession()
注入,否则它可能会崩溃。
Came here to understand how to mock URLSession
tasks such as URLSessionDataTask
?来到这里是为了了解如何模拟
URLSession
任务,例如URLSessionDataTask
?
Circa Swift 5, it is much easier to mock the URLProtocol
that URLSession
is using to send the request.大约5斯威夫特,这是很容易嘲笑
URLProtocol
是URLSession
使用发送请求。
See Unit Testing URLSession using URLProtocol.请参阅使用 URLProtocol 对 URLSession 进行单元测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.