概要
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が返ります。
正しい結果が得られた時のテストを書きます。
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に対してスタブを登録しています。
self.stub(http(.GET, uri: "http://api.pokosho.com/v1/hoge.json"), builder: json(body))
Alamofireの結果は非同期で帰ってくるため、QuickのtoEventuallyを使って、非同期に得られる値のチェックをしています。
今回はデフォルトのタイムアウトですが、引数でタイムアウトを指定することもできます。
expect(self.statusCode).toEventually(equal(200))
追記 URLパラメータを付加するとき
以下のように正規表現を使って、stubを登録するとうまくいきます?
self.stub(http(.GET, uri: "http://api.pokosho.com/v1/hoge.json?.*"), builder: json(body))
? ワイルドカードで hoge.json?*
かも…? よくわからない。すみません。
追記
- 最新のAlamofireだとスタブが効かないらしい。以下で回避できる。
NSURLSessionConfiguration.mockingjaySwizzleDefaultSessionConfiguration()
終わりに
http://pokosho.com は僕の使ってるドメインです^^;
iOSやその他のプログラミング情報もありますので、良かったらどうぞ。