1

私の Rails プロジェクトでは、VCRと RSpec を使用して、1 秒に 1 回しか呼び出しを許可しない外部 REST Web サービスに対する HTTP 相互作用をテストしています。

これが意味することは、Web サービスからの「呼び出し回数の超過」エラーが原因で失敗するまで、テスト スイートを実行することになるということです。ただし、その段階では、少なくともいくつかのカセットが録音されるため、最終的にすべてのカセットが録音され、スイートがカセットのみを使用して実行できるようになるまで、テスト スイートを継続的に実行します (my default_cassette_options = { record: :new_episodes })。これは最適な方法ではないように思えます。特に、将来頻繁にカセットを再録音する必要がある場合はなおさらです。絶え間ない呼び出しにより、Web サービスのブラックリストに登録されるのではないかと心配しています (テストはありません)。私が知っている彼らが持っているサーバー)。

sleep(1)そのため、Web サービスへの呼び出しが行われる直前にRspecブロックに呼び出しを入れてみることにitなり、それらの呼び出しを VCR 構成にリファクタリングしました。

仕様/サポート/vcr.rb

VCR.configure do |c|
  # ...
  c.after_http_request do |request, response|
    sleep(1)
  end
end

これはうまくいくように見えますが、これを行うためのより良い方法はありますか? 現時点では、まだカセットを持たない外部サービスへの呼び出しがスイートの最終テストである場合、スイートは不必要に 1 秒間スリープします。同様に、テスト スイートでカセットを使用しない 2 つの Web サービス呼び出しの間の時間が 1 秒を超える場合、別の不要な一時停止が発生します。これらの種類の条件をテストするためのロジックを作成した人はいますか、または VCR 構成でこれをエレガントに行う方法はありますか?

4

2 に答える 2

3

まず:new_episodes、記録モードとして使用しないことをお勧めします。用途はありますが、通常はデフォルト ( :once) が必要です。正確を期すために、単一パスで作成された一連の HTTP 要求としてカセットを記録します。を使用:new_episodesすると、数か月離れて記録された HTTP インタラクションを含むカセットがまとめて再生される可能性があり、実際の HTTP サーバーは同じように応答しない場合があります。

2 番目に、テストによって明らかになった問題に耳を傾け、テスト スイートのほとんどをこれらの HTTP リクエストから分離する方法を見つけることをお勧めします。クライアントに焦点を当てたテストと、エンドツーエンドの受け入れテストだけが要求を行うようにする方法を見つけることができますか? HTTP のものを単純なインターフェースでラップすると、他のすべてのテストをテストダブルに置き換えるのが簡単になり、入力をより簡単に制御できるようになります。

ただし、それは長期的な修正です。短期的には、次のように VCR 設定を微調整できます。

VCR.configure do |vcr|
  allow_next_request_at = nil
  filters = [:real?, lambda { |r| URI(r.uri).host == 'my-throttled-api.com' }]

  vcr.after_http_request(*filters) do |request, response|
    allow_next_request_at = Time.now + 1
  end

  vcr.before_http_request(*filters) do |request|
    if allow_next_request_at && Time.now < allow_next_request_at
      sleep(allow_next_request_at - Time.now)
    end
  end
end

これは、API ホストへの実際のリクエストでのみフックを実行するために、フック フィルター (ドキュメントに記載) を使用します。allow_next_request_at必要最小限の睡眠時間に使用されます。

于 2012-10-11T04:11:45.513 に答える
3

別の方法として、HTTP ライブラリのプロキシとして APICache を使用することもできます。これは、APICache が代わりにレート制限を処理するためです。

APICache.get("my_albums", period => 1) do
  FlickrRb.get_all_sets
end

これはAPICache::CannotFetch、API を制限よりも頻繁に呼び出そうとすると発生します。

APICache Github リポジトリへのリンクは次のとおりです。

于 2012-10-11T23:14:07.460 に答える