web-dev-qa-db-ja.com

AlamofireアプリでのHTTPトラフィックの単体テスト

Alamofireを使用してサーバーデータとの同期を支援するアプリを最適にテストする方法を見つけるのに少し苦労しています。

Alamofireを使用し、サーバーからのJSON応答を処理するコードをテストできるようにしたいと思います。実際のネットワークトラフィックを発生させずに予想される応答データをこれらのテストにフィードできるように、これらのテストをモックしたいと思います。

このブログ投稿( http://nshipster.com/xctestcase/ )では、Swift-しかし、私はよくわからないアラモファイアとその連鎖反応でそれを行うために。

マネージャーをm笑しますか?リクエスト?応答?助けていただければ幸いです!

32
Daniel D

私の意見では読みやすく使いやすいこのアプローチを見つけたので、別の答えを追加しています。

テストに必要な関数と型のみを含むダミーのAlamofireクラスを作成しました。ここで、実際のAlamofireではなく、このファイルをテストターゲットに含めます。

たとえば、テストに応じて検証するいくつかの静的変数を定義するRequestクラスのバージョンを作成し、このクラスではinitresponseJSON関数。

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")
}
21
MatterGoal

この質問は古くなってきていますが、私は同じ問題に遭遇したばかりで、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)
})
9
user541160

@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つの変数operationCompleteaccessTokenおよび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を手動で生成します。

それはあなたにとって意味がありますか?このテストが良いテストかどうかはわかりませんが、少なくともデータフローを確認できます。

1
MatterGoal