样例代码:
class NetworkManager {
func loadData(from url: URL,
completionHandler: @escaping (NetworkResult) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, _, error in
// Create either a .success or .failure case of a result enum
let result = data.map(NetworkResult.success) ?? .failure(error)
completionHandler(result)
}
task.resume()
}
}
可以由两种方法来mock数据。
// We create a partial mock by subclassing the original class
class URLSessionDataTaskMock: URLSessionDataTask {
private let closure: () -> Void
init(closure: @escaping () -> Void) {
self.closure = closure
}
// We override the 'resume' method and simply call our closure
// instead of actually resuming any task.
override func resume() {
closure()
}
}
class URLSessionMock: URLSession {
typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
// Properties that enable us to set exactly what data or error
// we want our mocked URLSession to return for any request.
var data: Data?
var error: Error?
override func dataTask(
with url: URL,
completionHandler: @escaping CompletionHandler
) -> URLSessionDataTask {
let data = self.data
let error = self.error
return URLSessionDataTaskMock {
completionHandler(data, nil, error)
}
}
}
//调整一下NetworkManager的实现
class NetworkManager {
private let session: URLSession
// By using a default argument (in this case .shared) we can add dependency
// injection without making our app code more complicated.
init(session: URLSession = .shared) {
self.session = session
}
func loadData(from url: URL,
completionHandler: @escaping (NetworkResult) -> Void) {
let task = session.dataTask(with: url) { data, _, error in
let result = data.map(NetworkResult.success) ?? .failure(error)
completionHandler(result)
}
task.resume()
}
}
//网络请求方法收敛为一个自定义方法
class NetworkManager {
private let session: NetworkSession
init(session: NetworkSession = URLSession.shared) {
self.session = session
}
func loadData(from url: URL,
completionHandler: @escaping (NetworkResult) -> Void) {
session.loadData(from: url) { data, error in
let result = data.map(NetworkResult.success) ?? .failure(error)
completionHandler(result)
}
}
}
//创建一个自定义的协议,该协议实现了该方法
protocol NetworkSession {
func loadData(from url: URL,
completionHandler: @escaping (Data?, Error?) -> Void)
}
//再让URLSession类来遵循该协议,并按需求实现该方法
extension URLSession: NetworkSession {
func loadData(from url: URL,
completionHandler: @escaping (Data?, Error?) -> Void) {
let task = dataTask(with: url) { (data, _, error) in
completionHandler(data, error)
}
task.resume()
}
}
//最后创建一个自定义mock类并遵循该协议,在该方法里返回指定的Mock数据。
class NetworkSessionMock: NetworkSession {
var data: Data?
var error: Error?
func loadData(from url: URL,
completionHandler: @escaping (Data?, Error?) -> Void) {
completionHandler(data, error)
}
}