情况:使用Rspec,FactoryGirl和VCR测试rails应用程序。
每次创建用户时,都会通过Stripe的API创建关联的Stripe客户。在测试时,在涉及用户创建的每个规范中添加VCR.use_cassette
或describe "...", vcr: {cassette_name: 'stripe-customer'} do ...
并没有多大意义。我的实际解决方案如下:
RSpec.configure do |config|
config.around do |example|
VCR.use_cassette('stripe-customer') do |cassette|
example.run
end
end
end
但这是不可持续的,因为每个http请求都会使用相同的磁带,这当然非常糟糕。
问题:如何根据个别要求使用特定灯具(磁带),而无需为每个规格指定磁带?
我有这样的想法,伪代码:
stub_request(:post, "api.stripe.com/customers").with(File.read("cassettes/stripe-customer"))
相关的代码片段(作为gist):
# user_observer.rb
class UserObserver < ActiveRecord::Observer
def after_create(user)
user.create_profile!
begin
customer = Stripe::Customer.create(
email: user.email,
plan: 'default'
)
user.stripe_customer_id = customer.id
user.save!
rescue Stripe::InvalidRequestError => e
raise e
end
end
end
# vcr.rb
require 'vcr'
VCR.configure do |config|
config.default_cassette_options = { record: :once, re_record_interval: 1.day }
config.cassette_library_dir = 'spec/fixtures/cassettes'
config.hook_into :webmock
config.configure_rspec_metadata!
end
# user_spec.rb
describe :InstanceMethods do
let(:user) { FactoryGirl.create(:user) }
describe "#flexible_name" do
it "returns the name when name is specified" do
user.profile.first_name = "Foo"
user.profile.last_name = "Bar"
user.flexible_name.should eq("Foo Bar")
end
end
end
我结束了这样的事情:
VCR.configure do |vcr|
vcr.around_http_request do |request|
if request.uri =~ /api.stripe.com/
uri = URI(request.uri)
name = "#{[uri.host, uri.path, request.method].join('/')}"
VCR.use_cassette(name, &request)
elsif request.uri =~ /twitter.com/
VCR.use_cassette('twitter', &request)
else
end
end
end
答案 0 :(得分:12)
VCR 2.x包含一项专门用于支持以下用例的功能:
https://relishapp.com/vcr/vcr/v/2-4-0/docs/hooks/before-http-request-hook! https://relishapp.com/vcr/vcr/v/2-4-0/docs/hooks/after-http-request-hook! https://relishapp.com/vcr/vcr/v/2-4-0/docs/hooks/around-http-request-hook!
VCR.configure do |vcr|
vcr.around_http_request(lambda { |req| req.uri =~ /api.stripe.com/ }) do |request|
VCR.use_cassette(request.uri, &request)
end
end
答案 1 :(得分:2)
IMO,像这样的图书馆应该为你提供一个模拟课程,但没有。
您可以使用Webmock进行伪代码示例,这是VCR使用的默认互联网模拟库。
body = YAML.load(File.read 'cassettes/stripe-customer.yml')['http_interactions'][0]['response']['body']['string']
stub_request(:post, "api.stripe.com/customers").to_return(:body => body)
您可以将它放在仅在某个标记上运行的前块中,然后标记发出API调用的请求。
在他们的测试中,他们会覆盖委托给RestClient(link)的方法。您也可以这样做,看看他们的测试套件,看看他们如何使用它,特别是他们使用test_response。我认为这是一种非常hacky做事的方式,并且会感到非常不舒服(注意我是少数人有这种不适)但它现在应该工作(它有可能在你知道直到运行时才会破坏)。如果我这样做,我想为两个模拟构建真实对象(一个模拟休息客户端,另一个模拟其余客户端响应)。
答案 2 :(得分:-1)
VCR的重点(主要是无论如何)只是为了重放先前请求的响应。如果你在那里挑选并选择回应什么样的请求,你就引用/取消引用它做错了。
就像约书亚已经说过的那样,你应该使用Webmock来做这样的事情。无论如何,这就是录像机在幕后的作用。