Alamofireを使用してサーバーデータとの同期を支援するアプリを最適にテストする方法を見つけるのに少し苦労しています。
Alamofireを使用し、サーバーからのJSON応答を処理するコードをテストできるようにしたいと思います。実際のネットワークトラフィックを発生させずに予想される応答データをこれらのテストにフィードできるように、これらのテストをモックしたいと思います。
このブログ投稿( http://nshipster.com/xctestcase/ )では、Swift-しかし、私はよくわからないアラモファイアとその連鎖反応でそれを行うために。
マネージャーをm笑しますか?リクエスト?応答?助けていただければ幸いです!
私の意見では読みやすく使いやすいこのアプローチを見つけたので、別の答えを追加しています。
テストに必要な関数と型のみを含むダミーのAlamofireクラスを作成しました。ここで、実際のAlamofireではなく、このファイルをテストターゲットに含めます。
たとえば、テストに応じて検証するいくつかの静的変数を定義するRequest
クラスのバージョンを作成し、このクラスではinit
とresponseJSON
関数。
public class Request {
var request:String?
struct response{
static var data:NSHTTPURLResponse?
static var json:AnyObject?
static var error:NSError?
}
init (request:String){
self.request = request
}
public func responseJSON(options: NSJSONReadingOptions = .AllowFragments, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
completionHandler(NSURLRequest(URL: NSURL(string:self.request!)!), Request.response.data, Request.response.json, Request.response.error)
return self
}
}
これで、テストで応答をモックできます。
func testMytestFunction(){
var HTMLResponse = NSHTTPURLResponse(URL: NSURL(string: "myurl")!, statusCode: 200, HTTPVersion: "HTTP/1.1", headerFields: nil)
Request.response.data = HTMLResponse
Request.response.json = LoadDataFromJSONFile("MyJsonFile")
request(.POST, "myurl", parameters: nil, encoding: ParameterEncoding.JSON).responseJSON {
(request, response, JSON, error) -> Void in
// the JSON and response variable now contains exactly the data that you have passed to Request.response.data and Request.response.json
}
}
要求関数はここで定義されます:
public func request(method: Method, URLString: URLStringConvertible, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL) -> Request {
return Request(request: URLString.URLString)
}
public func request(URLRequest: URLRequestConvertible) -> Request {
return Request(request: "fakecall")
}
この質問は古くなってきていますが、私は同じ問題に遭遇したばかりで、OHHTTPStubsを使用するときの解決策は非常に簡単です。
OHHTTPStubsはNSURLSessionから取得した応答をモックするだけなので、Alamofireとうまく機能し、コードパスを非常によくカバーします。
たとえば、テストケースでは、以下を使用して応答をモックするだけです。
OHHTTPStubs.stubRequestsPassingTest({
(request: NSURLRequest) -> Bool in
return request.URL!.Host == "myhost.com"
}, withStubResponse: {
(request: NSURLRequest) -> OHHTTPStubsResponse in
let obj = ["status": "ok", "data": "something"]
return OHHTTPStubsResponse(JSONObject: obj, statusCode:200, headers:nil)
})
@matttによる回答を待っているコードの例を投稿します。
簡単なWebサービスを呼び出すClient
クラスがあるとしましょう。このクラスは、WSを使用してサインインを実行するuserSignIn
という関数を実装します。
これはuserSignIn
関数のコードです:
func userSignIn(
#email:String,
password:String,
completionHandler: (Bool, String?, NSError?) -> Void
)-> Void
{
var parameters:[String:AnyObject] = [
"email":email,
"password":password,
]
Alamofire.request(.POST, Client.urlPath, parameters: parameters, encoding: ParameterEncoding.JSON).responseJSON {
(request, response, JSON, responseError) -> Void in
// Setup callback params
// HERE WE INJECT THE "FAKE" DATA--------
var operationComplete = false
var accessToken:String?
var error:NSError?
// --------------------------------------
if let statusCode = response?.statusCode {
// Check for errors and build response data
(operationComplete, accessToken, error) = self.checkSignInResponse(statusCode, JSON: JSON)
}
// Call the completion handler
completionHandler(operationComplete, accessToken, error)
}
}
この関数の目的は、ユーザーから渡された情報が正しい場合にWebサービスからトークンを取得することです。
関数checkSignInResponse
(答えには役に立たないのでコードを報告しません)には、3つの変数operationComplete
、accessToken
およびerror
受信したJSON応答に応じて。
3つの変数に値があるので、それらを使用してcompletionHandler
を呼び出します。
この関数をモックする方法?!
応答をモックするには、userSignIn
関数をテスト関数に直接オーバーライドします(NSHipsterの記事で説明されています)。
func testUserSignIn_whenParamsAreInvalid(){
class MockClient:Client {
override func userSignIn(#email: String, password: String, completionHandler:
(Bool, String?, NSError?) -> Void) {
// Set callback params
var operationComplete = false
var accessToken:String? = nil
var error:NSError? = NSError(domain: "Testing", code: 99, userInfo: nil)
completionHandler(operationComplete, accessToken, error)
}
}
signInViewController!.client = MockClient()
signInViewController!.loadView()
fillRegisterFieldsWithDataAndSubmit(femail(), password: fpassword())
XCTAssertNotNil(signInViewController!.error, "Expect error to be not nil")
}
次に、「模擬」クライアントを使用してテストしているView Controller内のclient
を置き換えます。この場合、コントローラーが無効の関数情報に渡すことをテストしているため、コントローラーのerror
プロパティがnilでないことを確認します。このデータを強制するには、単にoperationComplete
をfalseに設定し、NSError
を手動で生成します。
それはあなたにとって意味がありますか?このテストが良いテストかどうかはわかりませんが、少なくともデータフローを確認できます。