Rails で webmock と vcr の環境を作るメモ
Rails で外部Webサービスの API を叩く spec を書く際に、HTTP通信を mock にしたくなったので webmock と vcr を使ってみた。
これらを使うと初回だけリアルな通信をして通信内容をファイルに保持してくれるので、2回目以降はリアルな通信なしに spec を動かすことが出来る。 保持したデータは git に登録しておけば他のメンバがテストを動かしてもリアルな通信が発生しない。これは便利!
ググればどこにでも書いてるような内容だけど、自分用に導入手順をメモしておく。
前提
- rspec を使っている
導入手順
- Gemfile の
test
にwebmock
とvcr
を追加してbundle install
spec/rails_helper.rb
にrequire 'webmock/rspec'
を追加spec/support/vcr.rb
を追加して以下を記述
VCR.configure do |c| c.cassette_library_dir = 'spec/cassettes' c.hook_into :webmock c.configure_rspec_metadata! c.ignore_localhost = true end
- spec ファイルの
scenario
またはdescribe
に vcr の記述を追加。 (:hoge_fuga
は任意の文字列)
scenario 'hoge の fuga を確認する', vcr: { cassette_name: :hoge_fuga } do
実行
- 普通に rspec を実行すると1回目に
spec/cassettes/hoge_fuga.yml
が作成され、実際の通信のデータが記録される。 (初回はリアルな通信が走るので注意) - 2回目以降は上記ファイルのレスポンスを返すようになる
- spec 毎に
cassette_name
を変えておけばそれぞれの通信内容を保持できる。 - 必要なら生成された yml を直接編集して挙動を変えることも出来る。
トラブルシューティング
既存の Rails プロジェクトに webmock
と vcr
を導入すると、すでに HTTPリクエストを行なっている spec で以下のように軒並みエラーになってしまう。
VCR::Errors::UnhandledHTTPRequestError: ================================================================================ An HTTP request has been made that VCR does not know how to handle: POST https://slack.com/api/auth.revoke There is currently no cassette in use. There are a few ways you can configure VCR to handle this request: * If you're surprised VCR is raising this error and want insight about how VCR attempted to handle the request, you can use the debug_logger configuration option to log more details [1]. * If you want VCR to record this request and play it back during future test runs, you should wrap your test (or this portion of your test) in a `VCR.use_cassette` block [2]. * If you only want VCR to handle requests made while a cassette is in use, configure `allow_http_connections_when_no_cassette = true`. VCR will ignore this request since it is made when there is no cassette [3]. * If you want VCR to ignore this request (and others like it), you can set an `ignore_request` callback [4]. [1] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/debug-logging [2] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/getting-started [3] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/allow-http-connections-when-no-cassette [4] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/ignore-request ================================================================================
いくつか対策は提示されているけど、既存はそのまま HTTPアクセスしちゃっていい場合は spec/support/vcr.rb
に allow_http_connections_when_no_cassette = true
を追加してあげる。
VCR.configure do |c| c.allow_http_connections_when_no_cassette = true #++ c.cassette_library_dir = 'spec/cassettes' c.hook_into :webmock c.configure_rspec_metadata! c.ignore_localhost = true end
もしくは mock 化しちゃいたい場合は、vcr: { cassette_name: :xxxxxxxxxx }
を付加してあげればいい。