SwiftのQuickでAlamofireを使った非同期のテストを書く

  • 69
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

HTTP通信を行うようなテストケースを書くには、通常、スタブを使います。
サーバが落ちていたりしてテストが失敗するケースがありますし、連続してリクエストするのはサーバのリソースを食いますし、遅いですし…。
SwiftのQuickでAlamofireを使ったテストを書くのに躓いたので、同じ人がいるかもと思い、筆(キーボード)を執りました。

環境

  • Xcode7(Swift2.0)
  • Quick
    • RSpec風にかけるテストライブラリです。
    • 非同期のテストも書け、今回はこの機能を使います。
    • XCTestなど他のテストフレームワークを使う場合は、TRVSMonitorとかで非同期のテストをするといいかもしれません(試してません)。TKRGuardはSwiftではマクロが使えないためか動きませんでした。
  • Nimble
    • Quickが依存するmatcher
  • Mockingjay
    • HTTPモックライブラリです。
    • 他にもOHHttpStubsが有名ですが、Quick + Alamofireとは相性が悪そうで断念。
  • Alamofire
    • 説明不要、事実上標準といっても過言ではないHTTPライブラリ
  • SwiftyJSON
    • こちらも有名なJSONパーサですね。

コード

http://api.pokosho.com/v1/hoge.json は以下のJSONを返す謎のAPIの予定です。

{ "name": "kaiba" }

が、まだ実装していないため、404が返ります。
正しい結果が得られた時のテストを書きます。

RequestHogeAPISpec.swift
import Quick
import Nimble
import Mockingjay
import Alamofire
import SwiftyJSON

class RequestHogeAPISpec: QuickSpec {
    var jsonData: JSON!
    var statusCode: Int = 0

    override func spec() {
        describe("hoge API") {
            context("when you request hoge API http://api.pokosho.com/v1/hoge.json") {
                beforeEach() {
                    // setup stub
                    let body = [ "name": "kaiba" ]
                    self.stub(http(.GET, uri: "http://api.pokosho.com/v1/hoge.json"), builder: json(body))
                }

                it("returns json") {
                    // request async
                    Alamofire.request(.GET, "http://api.pokosho.com/v1/hoge.json")
                        .responseJSON { request, response, result in
                            self.jsonData = JSON(result.value!)
                            self.statusCode = response!.statusCode
                        }
                    expect(self.statusCode).toEventually(equal(200))
                    expect(self.jsonData["name"]).toEventually(equal("kaiba"))
                }
            }
        }
    }
}

結果

Test Suite 'All tests' passed at 2015-10-12 23:42:19.177.
     Executed 1 test, with 0 failures (0 unexpected) in 0.041 (0.046) seconds

1つのテストが実行され、失敗はありませんでした!
(試しにわざと失敗になるように書き換えて見ると良いと思います)

解説

beforeEachでAPIのURLに対してスタブを登録しています。

RequestHogeAPISpec.swift
self.stub(http(.GET, uri: "http://api.pokosho.com/v1/hoge.json"), builder: json(body))

Alamofireの結果は非同期で帰ってくるため、QuickのtoEventuallyを使って、非同期に得られる値のチェックをしています。
今回はデフォルトのタイムアウトですが、引数でタイムアウトを指定することもできます。

RequestHogeAPISpec.swift
expect(self.statusCode).toEventually(equal(200))

追記 URLパラメータを付加するとき

以下のように正規表現を使って、stubを登録するとうまくいきます?

RequestHogeAPISpec.swift
self.stub(http(.GET, uri: "http://api.pokosho.com/v1/hoge.json?.*"), builder: json(body))

? ワイルドカードで hoge.json?* かも…? よくわからない。すみません。

追記

NSURLSessionConfiguration.mockingjaySwizzleDefaultSessionConfiguration()

終わりに

http://pokosho.com は僕の使ってるドメインです^^;
iOSやその他のプログラミング情報もありますので、良かったらどうぞ。