2012-07-11 106 views
11

在我的黄瓜支持目录vcr.rb我有以下几点:红宝石VCR宝石一直记录相同的请求

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 

我地理编码的城市名,这使得在谷歌地图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?

回答

21

很难确定你刚才发布的内容是怎么回事,但我可以更多地解释VCR是如何工作的,并对这种可能的原因做出一些猜测行为。

VCR使用request matchers尝试查找先前记录的HTTP交互以回放。在单个卡带会话期间,当回放HTTP交互时,它将被视为“已使用”,并且不会再次播放(除非您使用allow_playback_repeats选项)。

所以...这里有几个可能性浮现在脑海:

  • 也许VCR是无法匹配您的HTTP请求。你使用什么请求匹配器?有一些简单的方法来解决这个问题(见下文)。
  • 如果您没有使用:allow_playback_repeats(这是默认设置,我建议您使用VCR),那么如果您的测试中有多个重复请求正在进行,您看到的行为可能会发生 - 例如,也许是卡带只有一个匹配请求,但你测试使其中2个 - 这将回放一个和记录一个(因为你使用: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#==)是这样的基本操作,我很难想象一个错误。如果无法弄清楚,欢迎随时打开一个github问题(希望通过调试记录器输出和/或触发该代码的代码示例)。

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

+2

@Erik J - 如果有*任何人*你应该听[VCR](https://github.com/myronmarston/vcr/),那就是有人叫做Myron; – Gareth 2012-07-12 01:43:04

+0

谢谢,Myron,我希望你能通过;)我刚刚意识到我的回复标题包括“过期: - 周五,2012年7月13日18:31:50 GMT”,这是请求日期后24小时。录像机是否注意到这一点并尝试再次提出请求?如果是这样,有没有办法禁用? – 2012-07-12 18:49:33

+0

不,录像机根本不使用它。有一个[re_record_interval](https://www.relishapp.com/myronmarston/vcr/v/2-2-3/docs/cassettes/automatic-re-recording)选项,但没有看任何标题(它只是使用配置的时间间隔),它不会产生你所看到的重复的交互;它会取代旧的HTTP交互,而不是仅仅添加一个新的交互。 – 2012-07-12 23:22:10

2

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

看起来像:new_episodes使用一些奇怪的启发式来遏制什么新的请求和什么请求已经发生。在我们的例子中,它将两个不同的请求标记为相同的请求,导致无尽的调试时间 - 因为我们得到了RefundOk答案,CaptureRequest等等。最好不要使用:new_episodes ...

+0

而非':all',':none'切换你提到的,我推荐你使用':一次记录模式。当录像带已经被录制时,它的作用类似于“:none”,或者当它是一个新的录像带时作为“:all”。 – 2012-07-12 05:17:15

+0

你为':new_episodes'引用的“奇怪的启发式”只是配置的请求匹配器。他们在所有记录模式下工作相同。 ':new_episodes'的作用是它将记录与先前记录的请求不匹配的请求;相反,当发生这种情况时,':once'和':none'会引发错误。 – 2012-07-12 05:19:01

8

当我有类似的问题,我固定它通过使match_requests_on设置更加具体:

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