[英]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.