気づけば弊社に入社してから2年と2ヶ月が経っていました。ついて簡単に解説します。今回私が新規に作成したRailsアプリケーションは仮にここではomoikane(仮)と呼ぶことにします。omoikaneはリクエストがあると社内の汎用APIサーバにアクセスし、APIサーバから取得した情報を元にレスポンスを返すアプリケーションです。omoikaneの実装・構成そのものはさほど難しくなかったのですが、一つ問題点がありました。このアプリケーションはAPIのレスポンスの仕様が破壊的に変更された場合に正しく動作しなくなってしまいます。そのような変更を入れてしまわないためにはいくつかの選択肢が考えられます。気をつける関係するアプリのコードをよく調べて問題ないことを確認する関係各位*1に確認するテストコードを書いてCIでAPIの破壊が無いかチェックし続ける気をつけるのは大変なので、もちろんテストコードでチェックしておきたいものです。それにはomoikane側ではAPIのレスポンスをモックし、APIモックレスポンスを元にしたレスポンスが正しいかテストしAPI側ではomoikane側のリクエストを模したリクエストに対して、omoikane側が必要とするレスポンスとなっているかテストする必要があります。汎用APIとomoikaneが別のRailsアプリではなく、モノリシックRailsアプリの別エンドポイントなどであったならもっと簡単なテストで済んだでしょう。マイクロサービスのためにはしょうがない、がんばって書こうと言われたら書けるかもしれませんが、がんばるのは疲れます。議論から生まれたRack::VCRです。リクエストとそのレスポンスをVCRカセット形式で出力・またはVCRカセットのデータを元にモックサーバとして動作させることができるRackミドルウェアです。あるAPIへのリクエストとレスポンスを一度実行して記録することでテストデータを作成するのが通常のVCRであるのに対し、APIを提供する側があらかじめテストデータを生成するという考え方です。以下に今回のコード例とともにその役割を解説します。まとめてありますので、詳しく知りたい場合はそちらをご確認ください。リクエストの記録Rack::VCRの基本機能はリクエストのVCRカセットへの記録です。いうAPIアプリのspecでRack::VCRを利用してVCRカセットを記録します。Rack::VCR)endapi/config/initializers/rack_vcr.rbテスト実行時のみRackミドルウェアの先頭にRack::VCRを入れておきます。"cassette_name"のようなメタデータがついたspecでのみVCRカセットを記録するように設定しておくと、以下のように自然な形でVCRカセットを生成するspecを書くことができます。入れるなどリポジトリに入れない運用が適切です。リクエストのモックこれはRack::VCRの機能ではなくVCRの機能なのですが、Rack::VCRで記録したVCRカセットはテストに利用することができます。例ではrails-app/というapiを利用するRailsアプリのテストで上述のRack::VCRで生成したVCRカセットを利用しています。"cassete_name"のような指定があるspecでのみVCRカセットを利用するように設定します。...endrails-app/spec/controllers/books_controller_spec.rbリクエストの再生Rack::VCRは以下のように簡単なコードでVCRカセットを利用してレスポンスするモックサーバとして動作させることができます。このようなモックサーバーを使うことで、VCRカセットを直接扱えないRubyアプリケーション以外のアプリケーションでもVCRカセットを利用できます。appただしこれではどのリクエストでも一つのカセットのレスポンスのみ返すためあまり柔軟な利用ができません。よって以下のように"HTTP_X_VCR_CASSETTE"ヘッダが付与されたリクエストのみヘッダで与えられたカセットを使うようにします。appmock/config.ruこれを通常のRackアプリのように起動するだけで"HTTP_X_VCR_CASSETTE"ヘッダが付与されたリクエストのみヘッダで与えられたカセットを利用したモックレスポンスを返すようになります。Androidアプリのテスト上述のモックサーバを利用するとAndroidアプリなどVCRカセットを直接読めないアプリケーションのテストも可能になります。モックサーバを利用して以下のようなインターフェースのAPIクライアントクラスのテストします。path);}https://github.com/hogelog/rack-vcr-sample/blob/master/android-app/app/src/main/java/org/hogel/androidapp/ApiClient.javaテスト時にはHTTP_X_VCR_CASSETTEヘッダを追加で付与するためモック用APIクライントを利用することにします。等を直接読んでもらうとして、ちょっと工夫すると以下の様にアノテーションでどのVCRカセットを利用するかテスト毎に指定することが出来ます。先に書いた社内汎用APIとomoikaneにおいてはこれらの機能のうち記録とモックのみ利用しています。汎用APIのspecが生成したVCRカセットを使ってomoikaneのspecが成功することを確認、コミットのような流れでおこなっています。CIでは汎用APIのCIが走るとomoikane用のVCRカセットが生成され、S3にアップロードされる汎用APIのCIが完了した時にomoikaneのCIがキックされるomoikaneはテスト開始時にS3から最新のVCRカセットをダウンロードしてくるのように常に最新の汎用APIとomoikaneの組み合わせが正しく動作することをテストし続け、汎用APIに破壊的な変更をコミットしてしまった場合にすぐにCIでそれを検知できるようにしています。テスト追加の流れにある上記エラーを元に汎用APIにomoikaneが必要とするリクエストを投げるspecを追加、実行という部分は工夫すればもっと自動化できそうな気がするのですが、現状ちょっとがんばって目で読んで手で書く作業をしています。改善の余地があります。未来Rack::VCR自体はかなり汎用的な機能を提供するライブラリであり、ここに示した利用方法がベストプラクティスとは限りません。激論を交わし、Rack::VCRの改善なりそれ以外の何かなり、現状のRack::VCRでは足りないどこかを目指して頑張っているのでそのうちまた面白いものが生まれてくると思うので楽しみにお待ち下さい。弊社のテストエンジニアはRack::VCRのような開発ツールの開発・運用からテスト・開発プロセスそのものの改善など、弊社のエンジニアリングの中核部分を担う重要な役職です。すごい面白そうなので私自身も社内配置転換を願って参入しようかと思えるぐらいの役職なので、興味のある方はぜひ一度遊びに来てみてください。以前「サービス分割時の複雑性に対処...2016-03-16クックパッドにおける最近のMicroservices事例こんにちは。