Драгоценный камень Ruby 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

Я геокодирую названия городов, которые звонят в API Карт Google. Я пытаюсь записать и заглушить эти запросы, но он продолжает записывать одни и те же запросы в один и тот же файл 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 каждый раз, когда я пытаюсь найти тот же город?

Ответ 1

Трудно сказать, что происходит с тем, что вы опубликовали, но я могу объяснить немного больше о том, как работает VCR, и сделать некоторые догадки о возможных причинах такого поведения.

В видеомагнитофоне используется запрос для сопоставления, чтобы попытаться найти ранее записанное взаимодействие HTTP для воспроизведения. Во время сеанса одиночной кассеты, когда воспроизводится HTTP-взаимодействие, считается, что оно используется, и оно не будет воспроизводиться снова (если вы не используете allow_playback_repeats опция).

Итак... вот пара возможностей, которые приходят на ум:

  • Возможно, видеомагнитофон не соответствует вашим HTTP-запросам. Какие помощники запросов вы используете? Есть несколько простых способов устранения этого неполадки (см. Ниже).
  • Если вы не используете :allow_playback_repeats (по умолчанию и как я рекомендую использовать видеомагнитофон), тогда поведение, которое вы видите, может произойти, если в вашем тесте выполняется несколько повторяющихся запросов - например, возможно, в кассете есть только один соответствующий запрос, но вы тестируете 2 из них - это будет воспроизводить один и записывать один (поскольку вы используете :new_episodes).

Чтобы устранить эту проблему, я рекомендую использовать параметр debug_logger, чтобы видеомагнитофон распечатывал то, что он делает, и как он пытается сопоставить каждый запрос. Это должно дать вам представление о том, что происходит. Вы также можете переопределить любой встроенный запросчик запросов и предоставить свою собственную логику и/или установить контрольную точку в матчи:

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

Возможно, вы также столкнулись с ошибкой видеомагнитофона, хотя сравнение URI (с использованием String#==) - это такая основная операция, что мне трудно представить себе ошибку. Не стесняйтесь открывать проблему github (надеюсь, с выходом отладочного журнала и/или пример кода, который запускает это), если вы не можете понять это.

На боковой ноте я рекомендую использовать режим записи :once (по умолчанию), а не :new_episodes. :once никогда не будет записывать дополнительные HTTP-взаимодействия в существующую кассету - это позволяет только записывать кассету один раз. Если запрос не соответствует, он вызывает ошибку, предупреждающую вас о том, что он не может соответствовать. :new_episodes, с другой стороны, записывает любой запрос, который не может найти совпадение, а именно поведение, которое вы видите.

Ответ 2

Когда у меня была аналогичная проблема, я исправил ее, установив более точную настройку match_requests_on:

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

Ответ 3

У меня наблюдалось подобное поведение, так что я делаю в основном сохранение :none. Если возникнут какие-либо новые запросы, я использую :any, запустите часть тестового набора, который выполнил запросы, и вернул его в :none.

Кажется, что :new_episodes использует некоторые странные эвристики, чтобы определить, какие новые запросы и какие запросы уже произошли. В нашем случае он отметил два разных запроса к платежным шлюзам как одни и те же, что привело к бесконечным часам отладки - потому что мы получили ответ RefundOk на CaptureRequest и тому подобное. Лучше не используйте :new_episodes...