[英]How to mock response from AFNetworking with OCMock in Swift?
這是我獲取網絡客戶端實例的方式:
let networkClient = DBNetworkClient(baseURL: NSURL(string: "http://mysite.pl/api"))
我也有一種方法:
func citiesWithParameters(parameters: [String: String], completionBlock: DBSearchOptionHandler) {
GET("cities", parameters: parameters, success: { operation, response in
if let error = NSError(response: response) {
completionBlock([], error)
} else {
let cities = DBCity.parseCitiesWithDictionary(response as! NSDictionary)
completionBlock(cities, nil)
}
}) { operation, error in
completionBlock([], error)
}
}
這就是我所謂的方法:
networkClient.citiesWithParameters(parameters, completionBlock: { cities, error in
//do sth
})
這樣,我傳遞了一些參數,並從服務器獲得了REAL響應。 當我要求時,我想嘲笑那個回應。 這個怎么做?
func testCities() {
let mockNetworkClient = OCMockObject.mockForClass(DBNetworkClient.classForCoder())
//what should I perform here to be able to do sth like this:
let expectation = expectationWithDescription("")
mockNetworkClient.citiesWithParameters(["a": "b"]) { cities, error in
expectation.fulfill()
XCTAssertNotNil(cities)
XCTAssertNil(error) //since I know what is the response, because I mocked this
}
waitForExpectationsWithTimeout(10, handler: nil)
}
這就是在DBNetworkClient
定義我的方法GET
方式:
override func GET(URLString: String!, parameters: AnyObject!, success: ((AFHTTPRequestOperation!, AnyObject!) -> Void)!, failure: ((AFHTTPRequestOperation!, NSError!) -> Void)!) -> AFHTTPRequestOperation! {
return super.GET(URLString, parameters: parameters, success: { (operation, response) in
print("GET \(operation.request.URL)")
print("GET \(response)")
success(operation, response)
}, failure: { (operation, error) in
print("GET \(operation.request.URL)")
print("GET \(operation.responseObject)")
failure(operation, error)
})
}
一旦我能夠為我提供50英鎊的賞金 ,將幫助我做到這一點。
不幸的是, 為AFNetworking編寫模擬測試沒有幫助。 它對我不起作用。
我沒有使用Alamofire的經驗,所以我不知道在哪里聲明您的GET
方法,但是您絕對應該在此方法中添加citiesWithParameters
而不要使用citiesWithParameters
。
例如,如果在DBNetworkClient
聲明了DBNetworkClient
:
func testCities()
{
//1
class DBNetworkClientMocked: DBNetworkClient
{
//2
override func GET(URLString: String!, parameters: AnyObject!, success: ((AFHTTPRequestOperation!, AnyObject!) -> Void)!, failure: ((AFHTTPRequestOperation!, NSError!) -> Void)!) -> AFHTTPRequestOperation! {
//3
success(nil, ["San Francisco", "London", "Sofia"])
}
}
//4
let sut = DBNetworkClientMocked()
sut.citiesWithParameters(["a":"b"]) { cities, error in
//5
XCTAssertNotNil(cities)
XCTAssertNil(error)
}
}
那么這里發生了什么:
DBNetworkClient
子類,因此按照您發布的文章中的描述為其創建“模擬”。 在該類中,我們將僅覆蓋我們要更改的方法(存根),並使其他方法保持不變。 這以前是使用OCMock完成的,稱為部分模擬。 DBNetworkClient
具有特定的構造函數,則必須調用此構造函數,而不是默認的構造函數-()。 到現在為止還挺好。 但是,如果GET
方法是Alamofire的一部分,則需要使用一種稱為“依賴注入”的技術(您可以在Google上搜索以獲得更多信息)。
因此,如果GET
在另一個類中聲明並且僅在citysWithParameters中引用,我們如何對它進行存根處理? 讓我們看一下:
//1
class DBNetworkClient
{
//2
func citiesWithParameters(parameters: [String: String], networkWorker: Alamofire = Alamofire(), completionBlock: DBSearchOptionHandler) {
//3
networkWorker.GET("cities", parameters: parameters, success: { operation, response in
if let error = NSError(response: response) {
completionBlock([], error)
} else {
let cities = DBCity.parseCitiesWithDictionary(response as! NSDictionary)
completionBlock(cities, nil)
}
}) { operation, error in
completionBlock([], error)
}
}
}
func testCities()
{
//4
class AlamofireMock: Alamofire
{
override func GET(URLString: String!, parameters: AnyObject!, success: ((AFHTTPRequestOperation!, AnyObject!) -> Void)!, failure: ((AFHTTPRequestOperation!, NSError!) -> Void)!) -> AFHTTPRequestOperation! {
success(nil, ["San Francisco", "London", "Sofia"])
}
}
//5
let sut = DBNetworkClient()
sut.citiesWithParameters(["a":"b"], networkWorker: AlamofireMock()) { cities, error in
//6
XCTAssertNotNil(cities)
XCTAssertNil(error)
}
}
citiesWithParameters
才能接收另一個參數。 此參數是我們的依賴項注入。 是具有GET
方法的對象。 在現實生活中的示例中,最好是僅使用協議,因為citiesWithParameters
不需要知道的其他信息超過該對象能夠發出請求的能力。 citiesWithParameters
所有調用citiesWithParameters
為新參數要求。 GET
方法 citiesWithParameters
時,我們將citiesWithParameters
對象作為networkWorker傳遞。 這樣,我們的存根GET
方法將被調用,我們將從“假”服務器中獲得期望的數據。 請注意,這兩個示例不使用OCMock,而是完全依靠Swift的力量! OCMock是一個很棒的工具,我們使用了很棒的動態語言-Objective-C。 但是,關於Swift的動態性和反思性幾乎完全消失了。 這就是為什么即使在OCMock官方頁面上我們也有以下聲明:
會不會有用Swift編寫的Swift模擬框架? 也許。 到目前為止,它看起來不太可能,因為模擬框架在很大程度上取決於對語言運行時的訪問,而Swift似乎沒有提供任何東西。
提供的兩個實現中缺少的是驗證調用GET
方法。 我將這樣保留它,因為這不是原始問題,您可以使用在模擬類中聲明的布爾值輕松實現它。
更重要的一點是,我假設Alamofire中的GET
方法是實例方法,而不是類方法。 如果不是這樣,則可以在DBNetworkClient
內部聲明一個新方法,該方法只需調用Alamofire.GET
並在citiesWithParameters
內部使用該方法。 然后,您可以像第一個示例一樣對這個方法進行存根,一切都會好起來的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.