如何簡單地模擬 NSURLSeesion 的返回數據
來自: 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>