I have Swift 2 code using Alamofire that queries a remote URL that it expects to return JSON. I've done enough interactive testing to be reasonably confident that it behaves correctly enough. Now I want to unit-test it so I can rely on this code and then move onto other things.
我使用Alamofire的Swift 2代码查询它希望返回JSON的远程URL。我做了足够的交互式测试,以确信其行为足够正确。现在我想对它进行单元测试,这样我就可以依赖这些代码,然后转向其他东西。
I'm new to Swift, although I've been programming OO Perl for decades, so there's probably something that I've missed.
我是Swift的新手,虽然我已经编写了几十年的OO Perl,所以我可能错过了一些东西。
Here's how I've set up the checking code so far (unimportant things such as how I get a username and password removed to avoid yak-shaving). The calling code specifies a username and password, and expects one of two callbacks to be called whenever a result is obtained. (I didn't get as far as dealing with errors, so please don't get side-tracked on that subject.)
这是我到目前为止设置检查代码的方式(不重要的事情,例如我如何删除用户名和密码以避免牦牛剃须)。调用代码指定用户名和密码,并且只要获得结果,就要调用两个回调中的一个。 (我没有处理错误,所以请不要对这个问题进行侧面跟踪。)
struct checkUsernameHandler {
var onSuccess: () -> ()
var onFailure: () -> ()
}
struct checkUsernameOutput {
var authenticated: Bool?
}
func checkUsername(user: User, handler: checkUsernameHandler) {
Alamofire.request(.PUT, NSURL(string: baseURL + "/user/verify?key=" + apiKey)!,
parameters: [
"username": user.username!,
"password": user.password!,
],
encoding: .JSON
).responseJSON { response in
let checkusernameOutput = self.analyseCheckUsernameResponse(response)
if let authenticated = checkusernameOutput.authenticated {
if authenticated {
handler.onSuccess()
} else {
handler.onFailure()
}
}
}
}
func analyseCheckUsernameResponse (response: Response<AnyObject, NSError>) -> checkUsernameOutput {
var output = checkUsernameOutput()
if (response.result.isSuccess) {
if let JSON = response.result.value as? NSDictionary {
// ...
}
} else {
print("Didn't get proper JSON or something: \(response.result.error)")
}
return output
}
What I'm looking for is a way of taking raw JSON and passing it to Alamofire somehow, so I can generate a response object that has the appropriate things in it, including errors if it didn't get anything (timeout?) or the data returned was invalid (e.g. an HTML-format 404 or 500 page).
我正在寻找的是一种获取原始JSON并以某种方式将其传递给Alamofire的方法,因此我可以生成一个具有相应内容的响应对象,包括错误,如果它没有得到任何东西(超时?)或者返回的数据无效(例如,HTML格式的404或500页)。
I'm happy enough at the moment with function checkUsername, so I'm not interested in anyone saying "use OHHTTPStubs". I'm looking at testing only the code that I'm uncertain about, which is the code I just wrote.
目前我对函数checkUsername感到高兴,所以我对任何说“使用OHHTTPStubs”的人都不感兴趣。我正在考虑只测试我不确定的代码,这是我刚写的代码。
EDIT: Having faffed about some more, it looks like Alamofire's internals are sufficiently connected that to create a fake Response, I need to do pretty much all of the work involved in setting up a network connection anyway. So perhaps the answer is "it's too much hassle to do that"?
编辑:对于更多的事情感到困惑,看起来Alamofire的内部已经充分连接到创建一个假的响应,我需要完成所有涉及建立网络连接的工作。所以也许答案是“这样做太麻烦了”?
1 个解决方案
#1
5
I had success by overriding the URLProtocol's startLoading method. You can find an example of this within Alamofire's test directory under URLProtocolTests.swift.
我通过覆盖URLProtocol的startLoading方法获得了成功。您可以在Alamofire的测试目录下的URLProtocolTests.swift下找到此示例。
By intercepting this call, one could capture the incoming request then parse the URL to match your chosen mock response. Below is an example of how I handle the response:
通过拦截此调用,可以捕获传入的请求,然后解析URL以匹配您选择的模拟响应。以下是我如何处理响应的示例:
override func startLoading() {
//Seperate module I used to handle the request
let data:NSData = mocks.find(request) as! NSData
let client = self.client
let response = HTTPURLResponse(url: (request.url)!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: cannedHeaders)
client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: URLCache.StoragePolicy.notAllowed)
cannedResponse = data
client?.urlProtocol(self, didLoad: cannedResponse as! Data)
client?.urlProtocolDidFinishLoading(self)
activeTask?.resume()
}
I posted a full example of how to do this on github here: https://github.com/ksteigerwald/MockAlamofire
我在github上发布了一个如何做到这一点的完整示例:https://github.com/ksteigerwald/MockAlamofire
#1
5
I had success by overriding the URLProtocol's startLoading method. You can find an example of this within Alamofire's test directory under URLProtocolTests.swift.
我通过覆盖URLProtocol的startLoading方法获得了成功。您可以在Alamofire的测试目录下的URLProtocolTests.swift下找到此示例。
By intercepting this call, one could capture the incoming request then parse the URL to match your chosen mock response. Below is an example of how I handle the response:
通过拦截此调用,可以捕获传入的请求,然后解析URL以匹配您选择的模拟响应。以下是我如何处理响应的示例:
override func startLoading() {
//Seperate module I used to handle the request
let data:NSData = mocks.find(request) as! NSData
let client = self.client
let response = HTTPURLResponse(url: (request.url)!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: cannedHeaders)
client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: URLCache.StoragePolicy.notAllowed)
cannedResponse = data
client?.urlProtocol(self, didLoad: cannedResponse as! Data)
client?.urlProtocolDidFinishLoading(self)
activeTask?.resume()
}
I posted a full example of how to do this on github here: https://github.com/ksteigerwald/MockAlamofire
我在github上发布了一个如何做到这一点的完整示例:https://github.com/ksteigerwald/MockAlamofire