如何簡單地模擬 NSURLSeesion 的返回數據

bofg5837 8年前發布 | 7K 次閱讀 iOS開發 Objective-C開發

來自: http://www.cocoachina.com/swift/20160205/15237.html

原文鏈接: http://swiftandpainless.com/an-easy-way-to-stub-nsurlsession/

作者: dom

原文日期:2016/01/09

</div>

如果你熟悉我這個博客的話,你可能知道我檢查問題時,最喜歡的方法是模擬 NSURLSeesion 返回的數據。

那么我們到底要做什么呢,其實是模擬方法的回調數據。而這里的 NSURLSession指的是偽造 web API 的響應。這樣做有一些好處,例如:

  • 我們不需要一個可用的 web API 來開發我們應用程序的網絡請求。

  • 能夠立馬響應,反饋周期更短。

  • 測試程序能在沒有網絡連接的電腦上運行。

一般來說,模擬 NSURLSession 的請求返回數據是通過 NSURLProtocol 來完成的。具體的用例請查看 OHHTTPStubs 和  Mockingjay 。使用 NSURLProtocol 的優勢在于,當你使用諸如 Alamofire 這樣的網絡請求庫時,也能正常模擬數據回調。這種方式很棒,但是對我來說代碼太多了。我必須去學習和理解這些代碼,以在我的測試中獲得預期的效果。

一個簡單的解決方案

我將使用 NSURLSession 來做網絡請求。下面是如何偽造我的請求返回數據。

為了讓它看起來更簡單,我已經寫了一個 NSURLSession 的替換類和一個協議。整合起來如下所示:

import Foundation
public protocol DHURLSession {
  func dataTaskWithURL(url: NSURL,
    completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask
  func dataTaskWithRequest(request: NSURLRequest,
    completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask
}
extension NSURLSession: DHURLSession { }
public final class URLSessionMock : DHURLSession {

var url: NSURL? var request: NSURLRequest? private let dataTaskMock: URLSessionDataTaskMock

public init(data: NSData?, response: NSURLResponse?, error: NSError?) { dataTaskMock = URLSessionDataTaskMock() dataTaskMock.taskResponse = (data, response, error) }

public func dataTaskWithURL(url: NSURL, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask { self.url = url self.dataTaskMock.completionHandler = completionHandler return self.dataTaskMock }

public func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask { self.request = request self.dataTaskMock.completionHandler = completionHandler return self.dataTaskMock }

final private class URLSessionDataTaskMock : NSURLSessionDataTask {

typealias CompletionHandler = (NSData!, NSURLResponse!, NSError!) -> Void
var completionHandler: CompletionHandler?
var taskResponse: (NSData?, NSURLResponse?, NSError?)?

override func resume() {
  completionHandler?(taskResponse?.0, taskResponse?.1, taskResponse?.2)
}

} }</pre>

如上,用來偽造數據的完整幫助代碼是 47 行。并且所有代碼清晰易懂,既沒有 swizzling,也沒有復雜的方法。是不是很棒!

使用

為了能夠在測試中使用 NSURLSession 替換類,我們需要在代碼中注入依賴。一種可能的方式是使用一個懶屬性:

lazy var session: DHURLSession = NSURLSession.sharedSession()

然后一個示例測試可能會是這樣的:

func testFetchingProfile_ReturnsPopulatedUser() {
  // Arrage
  let responseString = "{\"login\": \"dasdom\", \"id\": 1234567}"
  let responseData = responseString.dataUsingEncoding(NSUTF8StringEncoding)!
  let sessionMock = URLSessionMock(data: responseData, response: nil, error: nil)
  let apiClient = APIClient()
  apiClient.session = sessionMock

// Act apiClient.fetchProfileWithName("dasdom")

// Assert let user = apiClient.user let expectedUser = User(name: "dasdom", id: 1234567) XCTAssertEqual(user, expectedUser) }</pre>

我很喜歡這樣的解決方案,因為我只要花幾分鐘時間,通過閱讀五十多行代碼就能理解替換類。并且沒有涉及到 NSURLProtocol 和 swizzling。

這個 NSURLSession 的替換類在 github 上,并且也可以通過CocoaPods 下載。

讓我知道你的想法。

</div>

 本文由用戶 bofg5837 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!