Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

VCR Gem × WebMockでRubyのテストスイートを高速化する方法

Rubyアプリケーションが外部APIを利用しているなら、テストが遅い・APIのレート制限に引っかかるといった問題に直面したことがあるのではないでしょうか。

解決策は何があるでしょう?

クライアントライブラリのHTTPメソッドを手動でスタブ化し、事前に用意したレスポンスを返す方法もあります。

しかし、これは手間がかかる上に、コードも読みにくくなってしまいます。

より良い解決策は、WebMock + VCRという強力なGemの組み合わせを使うことです。

WebMockは、主要なHTTPライブラリからのHTTPリクエストを横取り(インターセプト)します。対応しているのは例えば:

  • net/http
  • Faraday
  • RestClient
  • …など多数!

これだけでも便利ですが、レスポンスデータは自分で用意する必要があります。

そこで登場するのがVCRです。

VCRはWebMockと連携し、コードが受け取ったHTTPレスポンスを記録します。

この記録ファイルは「カセット(cassette)」と呼ばれます。

テスト実行時には:

VCRがカセットファイルを読み込み、記録済みのレスポンスを返します。実際のAPIに問い合わせる必要がないため、応答速度が大幅に向上します。

それでは、具体的なコード例を見ていきましょう。

VCRのコード例

この例ではRSpecを使用します。後ほど説明するように、RSpecはVCRとの相性が抜群だからです。

テスト対象となるコードはこちら:

require "faraday"
require "json"

class Github
  def self.user(name)
    url  = "https://api.github.com/users/#{name}"
    data = Faraday.get(url).body

    JSON.parse(data, symbolize_names: true)
  end
end

Github APIにリクエストを送り、特定ユーザーの情報を取得するシンプルなコードです。シンプルですが、VCRの仕組みを学ぶには十分な題材になります。

このコードに対するテストは次のように書けます:

require "rspec/autorun"

require_relative "github_api_example"

describe Github do
  let(:user_response) { Github.user("ruby") }

  it "can fetch & parse user data" do
    expect(user_response).to be_kind_of(Hash)

    expect(user_response).to have_key(:id)
    expect(user_response).to have_key(:type)
  end
end

このテストは実際のAPIにアクセスしてパスしますが、完了まで約0.5秒かかります。

たった1つのテストで0.5秒です!

大したことはないように思えますが、100個のテストがあれば、全部の実行に50秒かかる計算になります。

これを改善していきましょう。

まず、以下のコードを追加してVCRを導入します:

require "vcr"

VCR.configure do |c|
  c.cassette_library_dir = "spec/vcr"
  c.hook_into :webmock
end

このコードはtest_helperファイルなどに記述しておくと、すべてのテストから利用できるようになります。

このconfigureブロックでは、カセットファイルの保存先を指定し、WebMockとの連携を有効にしています。

FaradayやExconを使っている場合は、VCRはそれらに直接フックすることも可能です。

その場合は:webmock:faraday:exconに置き換えるだけです。

次に:

カセットの名前と、そのカセットのもとで実行すべきコードをVCRに教える必要があります。

書き方はこちら:

let(:user_response) do
  VCR.use_cassette("github/user") { Github.user("ruby") }
end

テストを実行すると、VCRはcassette_library_dir配下にファイルを作成します。この場合、ファイル名はspec/vcr/github/user.yamlになります。実際に試してみる方は、ぜひ中身を覗いてみてください。

この状態でテストを実行すると、格段に速くなります

なんと…

わずか0.01秒で完了します!

「An HTTP request has been made that VCR does not know how to handle」というエラーが出たら

このエラーメッセージが出る原因は主に2つあります。

1. VCRが有効な状態でHTTP呼び出しを行っているが、VCR.use_cassetteブロックの外で実行している。

解決策: デフォルトでは、VCR + WebMockはすべてのHTTPリクエストをブロックします。設定オプションで挙動を変更するか、不足しているVCRブロックを追加するか、RSpecメタデータ(次のセクション)を利用しましょう。

2. 別のリクエストを行おうとしているのに、URLが一致しないカセットを使おうとしている。たとえば、テストで/users/rubyにリクエストした場合、カセットはこのURL専用に作成されます。テストを/users/appleに変更すると、カセットが別のURL向けのため、このエラーが発生します。

解決策: URLごとに異なるカセットを使う、new_episodes記録モードを有効にする(vcr: { record: :new_episodes })、またはリクエストURLを更新した後に古いカセットを削除する、のいずれかを行いましょう。

RSpecメタデータの使い方

VCR.use_cassetteメソッドは、このGemを使う基本的な方法です。

しかし…

VCRにカセットを自動生成させることもできます。

どうやって?

VCR.configureブロック内に次の1行を追加します:

c.configure_rspec_metadata!

これで、特定のテスト(itブロック)やテストグループ(describe)に対してVCRを有効化できるようになります。

こんな感じです:

describe Github, :vcr do
  # ...
end

すると、テストの説明文に基づいた名前のカセットファイルが作成されます:

spec/vcr/
└── Github
    ├── can_parse_user_data.yml
    └── can_test_vcr.yml

注意点として、この方法ではテストごとに1つのカセットが作成されます。

2つのテストが同じリクエストを行い、同じデータを使っていたとしても、VCRはそれぞれ別々のカセットを作成します。

便利なVCRのオプションとヒント

カセットに問題がある場合や、最新のデータが必要な場合は、カセットファイルを削除してみましょう。

VCRが新しいAPIレスポンスを記録し直すので、問題が解決することがあります。

それでも解決しない場合は?

VCR.configureデバッグモードを有効にできます:

VCR.configure do |c|
  # ...
  c.debug_logger = $stderr
end

大量の出力が生成される可能性があるため、関心のあるテストだけに絞って実行してください。

次に:

APIキーなど、機密性の高いデータがAPIレスポンスに含まれているとしましょう。

そうしたデータは記録から除外したいはずです。

その方法はこちら:

VCR.configure do |c|
  # ...
  c.define_cassette_placeholder("<API_KEY>", ENV["API_KEY"])
end

まとめ

WebMockとVCRというGemを使うことで、外部APIのレスポンスを待つことなく、Rubyアプリのテストを快適に書けるようになりました!

VCR Gem × WebMockでRubyのテストスイートを高速化する方法

この記事が役に立ったら、ぜひシェアして更多人に届けてください。

最後までお読みいただきありがとうございました 🙂


  1. AASM Gemで学ぶRubyステートマシン入門|Stateデザインパターンから実践的な使い方まで

    今回は、ステートマシン(状態遷移マシン)の仕組みと、RubyプロジェクトでAASM gemを使ってステートマシンを活用する方法を解説します。 まずは身近な例から考えてみましょう。 信号機を想像してください。信号機は「赤」「黄」「青」のいずれかの状態を取ります。 そして、色が変わるとき、次に何色になるかは現在の色によって決まっています。 ここでは、視覚障害のある方が渡れるタイミングを音で知らせるタイプの信号機だとしましょう。 さて、ここからが本題です。 あなたがこの信号機のソフトウェアを開発することになったとします。 毎回どの音を鳴らすべきか、次はどの色に変わるべきか——それをどう判断すればよ

  2. スクリーン録画で生産性を向上させる方法|活用シーンとおすすめツールを徹底解説

    パソコンの作業効率を高めてくれるソフトウェアをお探しですか?そのリストに必ず加えておきたいのが、スクリーン録画(画面収録)ツールです。なぜスクリーン録画ソフトが必要なのでしょうか?また、どのような場面で活躍するのでしょうか?本記事では、スクリーン録画のメリットと具体的な活用法、さらにおすすめツールまで詳しくご紹介します。 なお、当サイトでは生産性向上に役立つおすすめのタイムトラッキング(時間管理)ソフトも紹介しています。こちらもぜひ併せてチェックしてみてください。 スクリーン録画ソフトがもたらす5つのメリット 1. チュートリアルや研修動画を簡単に作成できる 現在、業務の多くは複数のアプリケー