HTTPアクセスを記録/再生してテスト時に使える、Betamaxを試してみたよ
「初夢が別の人と結婚する夢だった」と妻に話したら、「私も別の人と結婚してる夢を見て、子供も産まれてた」と返されて負けた気がしたikikkoです。あけましておめでとうございます。今年もよろしくお願いします。
概要
Betamax - Record / playback testing proxyとは・・・うまく説明できる気がしないので、丸ごと引用してきます。
BetamaxはWebへのアクセスを記録して再生することのできるrecord/playback proxy です。
最 近 の ア プ リ ケ ー シ ョ ン は Twitter や Facebook な ど 外 部 のWebAPIと連携するものが多くなってきていますが、Betamaxを利用すると実際にWebAPI やWebサイトへのアクセスを行わずにアプリケーションのテストを行うことができます。
Betamax はHTTP リクエスト・レスポンスのペアを、HTTP リクエストの内容をキーとして「tape」というテキストファイル(YAML) に記録します。テストケースに対してtapeを指定してやることで、既に記録済みのHTTP リクエストに対してはtape の内容が再生されます。未記録のHTTPリクエストであれば、実際に得られたレスポンスをキャプチャしてtape に記録します。
http://grails.jp/g_mag_jp/file/gmagazine_4.pdf
Groovyカテゴリに入れてますが、JUnitをはじめとしたJavaオンリーでも多分使うことができます(未検証)。
もうちょっとちゃんとした説明は、下記を参考にしてください(説明されている内容はどちらも大体同じです)。
メリット
いくつか参考資料中でも述べられていますが、外部にアクセスにいかないので下記のようなメリットがあります。
- オフラインでテスト実行できる
- スローテスト問題を解決できる
- (ネットワークや接続先での障害といった)外部環境の影響を受けにくい
- 更新系APIでの副作用問題が起きない
また、通信データを加工できるので
- レアケースを簡単に再現できる
- (認証情報などの)共有するべきでない個人情報を除去した上で、データを共有できる
というのもあげられるでしょう。
外部APIを使ったテストには、ダミーのモックを使うという選択肢もあります。ただ、Betamaxでは実際の通信データを再利用するので、まるごとモックを用意するよりは信頼できるデータといえるでしょう。
サンプル
サンプルでは、Cacoo APIを使っています。具体的には、図の新規作成/コメントの追加をCacoo API経由で行い、そのレスポンスから最新のコメントを取得するものです。Cacoo APIを含んだコードでも、毎回外部(Cacoo)に接続しに行かずにテストします*1。
サンプルコードは、Githubの下記の場所に置いています。Gradleでプロジェクトを作成しておりGradle Wrapperも用意しているので、cloneして"./gradlew test"と入力すればサンプルを実行することができます(Groovy環境も必要ありません)。テスト実行後、"build/reports/tests/index.html"で実行結果や出力を確認できます。
解説
メインのコードは以下です。
Betamaxの設定は大きくわけて、下記の2点です。
- @RuleにRecorderを設定する
- 各テストケースに@Betamaxを指定する
まず、RuleにRecorderを設定します。これは、単純に宣言するだけで十分です。
// Betamaxを使用して、通信内容をtapeに記録/読込できるようにする @Rule Recorder recorder = new Recorder()
@Betamaxでは、tapeの保存先を指定します。また、tapeから読み込むときの判定条件を「リクエストの(ホスト名+パス)が一致したとき」というように変更しています。デフォルトだとURI一致なのですが、今回はAPI Keyをクエリーストリングに含むのでURIが変わる可能性があったので、このようにしています。
// 保存先のtape名を指定, ホスト名/パスが一致した場合はtapeから読み込む(クエリは判定対象外) @Betamax(tape="create diagram", match=[ MatchRule.host, MatchRule.path ]) def "図の新規作成"() { ... }
tapeの記録
通信内容をtapeに記録するために、初回はHTTP通信が発生します。記録された通信内容は、YAML形式で保存されます。以下のファイルが、tape内容です。
- 図の新規作成
- コメントの追加
Cacoo APIを使う場合はAPI Keyが必要ですし、記録されたtapeにもAPI Keyも合わせて記録されています。ですが、push前に上記のtapeを直接編集して、API Keyの情報を除去しました。このように、一度tapeを作成してから、都合がいいようにデータを改ざんできるのもメリットの一つです。
tapeの再生
2回目以降は、作成されたtapeを元に通信が再生されます。以降はネットワークにつながっている必要がありません。また、API Keyを設定しておく必要もありません。
pushをしたものはすでにtapeの記録を行った状態なので、再生から実行することができます。
問題点・注意事項
HTTPSをサポートしていない
一番大きいのはHTTPSをまだサポートしていないということ。Issueとしてあがっているので認識はしていると思うのですが、いつサポートされるのかは分かりません。
これサポートされないと、多分厳しいよな・・・
HttpClientを使う場合は、Proxyの設定が必要
Betamaxでは、実行時にJavaのProxy設定をいじってBetamaxが起動しているサーバ(デフォルトではlocalhost, 5555)に向けます。ただ、HttpClientのデフォルト設定では、JavaのProxyの設定を参照しないようです。HttpClient(や内部でBetamaxを使っているHttpBuilder)でもBetamaxを使うために、ちょっと設定を追加する必要があります。サンプルコードではHttpBuilderを使っているので、それ用の設定も追加しています。
詳しくは、下記を参照してください。
公式サイトのドキュメントとリリース版のモジュールが一致していない
これにしばらくハマりました。ドイヒーですよね。
公式サイトにまだリリースされていない機能も書かれています。具体的には、betamax.propertiesというプロパティファイルでいくつか設定を変更できるのですが、これのignoreHosts/ignoreLocalhostが現在リリースバージョンの1.0には含まれていません。
他にもあるかもしれないので、注意しましょう。
どうでもいいですが、テニスの王子様って面白いですよね (・∀・)