12

在我的黄瓜支持目录中,我在 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

4 回答 4

21

很难确定您发布的内容发生了什么,但我可以更多地解释 VCR 的工作原理,并对这种行为的可能原因进行一些猜测。

VCR 使用请求匹配器来尝试查找先前记录的 HTTP 交互以进行回放。在单个磁带会话期间,当一个 HTTP 交互被播放时,它被认为是“使用的”并且不会再次播放(除非您使用allow_playback_repeats选项)。

所以......这里有几种可能性:

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

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

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#==)是一个非常基本的操作,以至于我很难想象那里有错误。如果您无法弄清楚,请随意打开一个 github 问题(希望使用调试记录器输出和/或触发此问题的代码示例)。

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

于 2012-07-12T01:40:13.147 回答
9

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

VCR.configure do |c|
    c.default_cassette_options = {
        match_requests_on: [:uri, :body, :method]
    }
end
于 2014-02-14T19:18:24.167 回答
2

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

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

于 2012-07-11T21:28:28.007 回答
0

如果您未定义匹配参数,则将 Elasticsearch 与 VCR 一起使用将始终重新生成磁带。我必须将匹配定义为仅:method因为:uriand: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
于 2020-12-03T11:03:51.920 回答