Ruby VCR gem会记录相同的请求

时间:2012-07-11 21:03:01

标签: ruby-on-rails ruby rspec cucumber vcr

在我的黄瓜支持目录中,我在vcr.rb中有以下内容:

require 'vcr'

VCR.configure do |c|
  c.cassette_library_dir = 'fixtures/vcr_cassettes'
  c.hook_into :webmock
  c.ignore_localhost = true
  c.default_cassette_options = { record: :new_episodes }
end

我正在对城市名称进行地理编码,从而调用Google Maps API。我正在尝试记录和存根这些请求,但它会将相同的请求记录到同一个yml文件中:

- request:
    method: get
    uri: http://maps.googleapis.com/maps/api/geocode/json?address=Miami,%20FL&language=en&sensor=false
    body:
      encoding: US-ASCII
      string: ''
    headers:
      Accept-Encoding:
      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
      Accept:
      - ! '*/*'
      User-Agent:
      - Ruby
  # response...

- request:
    method: get
    uri: http://maps.googleapis.com/maps/api/geocode/json?address=Miami,%20FL&language=en&sensor=false
    body:
      encoding: US-ASCII
      string: ''
    headers:
      Accept-Encoding:
      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
      Accept:
      - ! '*/*'
      User-Agent:
      - Ruby

它是相同的URL和非常相同的请求,不应该VCR存根请求?每当我尝试搜索同一个城市时,如何阻止我的规范访问API?

4 个答案:

答案 0 :(得分:21)

很难确定您发布的内容是什么,但我可以更多地解释VCR如何工作并对可能的原因做出一些猜测。

VCR使用request matchers尝试查找以前录制的HTTP互动进行回放。在单个磁带盒会话期间,当播放HTTP交互时,它被认为是“已使用”并且不会再次播放(除非您使用allow_playback_repeats选项)。

所以......我想到了几种可能性:

  • 可能VCR无法匹配您的HTTP请求。您使用的是哪些请求匹配器?有一些简单的方法可以解决这个问题(见下文)。
  • 如果您没有使用:allow_playback_repeats(这是默认设置,以及我建议您使用VCR的方式),那么如果您的测试中出现多个重复请求,则可能会发生您所看到的行为 - 例如,也许录音带只有一个匹配的请求,但你正在测试它们中的两个 - 这将播放一个并记录一个(因为你正在使用:new_episodes)。

要解决此问题,我建议您使用debug_logger选项让VCR打印它正在做的事情以及它如何尝试匹配每个请求。这应该可以让您深入了解正在发生的事情。您还可以覆盖任何the built in request matchers并在匹配器中提供自己的逻辑和/或设置断点:

VCR.configure do |c|
  c.register_request_matcher :uri do |request_1, request_2|
    debugger # so you can inspect the requests here
    request_1.uri == request_2.uri
  end
end

你可能也遇到过VCR错误,虽然比较URI(使用String#==)是一个基本的操作,我很难想象那里有一个bug。如果您无法解决问题,请随意打开github问题(希望调试记录器输出和/或触发此问题的代码示例)。

另外,我建议您使用:once记录模式(默认值)而不是:new_episodes:once永远不会记录与现有磁带相关的额外HTTP交互 - 它只允许录制一次磁带。如果请求无法匹配,则会引发错误,提醒您无法匹配的事实。另一方面,:new_episodes将记录任何无法找到匹配项的请求,这就是您所看到的行为。

答案 1 :(得分:8)

当我遇到类似的问题时,我通过使match_requests_on设置更具体来修复它:

VCR.configure do |c|
    c.default_cassette_options = {
        match_requests_on: [:uri, :body, :method]
    }
end

答案 2 :(得分:2)

我经历过类似的行为,所以我所做的基本上是设置为:none。如果出现任何新请求,我会使用:any,运行执行请求的测试套件部分并将其设置回:none

似乎:new_episodes使用了一些奇怪的启发式方法来检测新请求是什么以及已经发生了什么请求。在我们的案例中,它将支付网关的两个不同请求标记为相同的请求,导致无休止的调试时间 - 因为我们得到了RefundOk CaptureRequest的答案等等。最好不要使用:new_episodes ...

答案 3 :(得分:0)

如果未定义匹配参数,则将Elasticsearch与VCR一起使用将始终重新生成盒带。我必须将匹配定义为仅:method,因为:uri:body可以在每次测试运行时更改。

VCR.configure do |c|
  c.hook_into :webmock
  c.ignore_localhost = true
  c.configure_rspec_metadata!
  c.cassette_library_dir = 'spec/cassettes'
  c.default_cassette_options = { record: :new_episodes,
                                 match_requests_on: [:method] }
end