Getting Started with WebMock and VCR

Jon Homan, Mar 30, 2011

Last time, I introduced what WebMock and VCR can do for you. Now, let’s see what we need to do to get them set up in a Rails 3 application in our RSpec and Cucumber tests.

Note, for this post, we won’t cover using WebMock separately from VCR, but you can see how I use WebMock without VCR’s recorded responses to test the Twitter OAuth handshake in this commit.

Okay, let’s get started. The first thing you will need to do is add WebMock and VCR to your project’s Gemfile.

gem 'webmock', '1.6.2'
gem 'vcr', '1.6.0'

Now, we need to make sure our tests load up the WebMock library. Assuming you are using RSpec and Cucumber, edit spec/spec_helper.rb and features/support/env.rb to require WebMock.

# spec/spec_helper.rb
require 'webmock/rspec'
# features/support/env.rb
require 'webmock/cucumber'

WebMock also supports Test::Unit. For information on configuration, take a look atwebmock’s documentation.

We also need to configure vcr. Edit spec/spec_helper.rb.

require 'vcr'

And inside of the RSpec.configure block:

# Gives you 'use_vcr_cassette' as a macro
config.extend VCR::RSpec::Macros

Now create a new file in spec/support called vcr.rb and add the following:

require 'vcr'

VCR.config do |c|
c.cassette_library_dir = 'fixtures/cassette_library'
c.stub_with :webmock
c.ignore_localhost = true
c.default_cassette_options = { :record => :none }
end

Let’s quickly go over the configuration options:

  • cassette_library_dir sets up the directory where your recorded responses will be stored.
  • stub_with tells VCR which library to use to fake the HTTP requests.
  • ignore_localhost tells VCR whether or not to allow local requests.
  • default_cassette_options set up defaults for recording, re-record, etc.

Now to use VCR in our specs. First, we need to set up the cassette we want VCR to use. I do this this at the beginning a spec file, generally right after the initial describe.

describe Feed do
use_vcr_cassette "feed", :record => :new_episodes

....

end

The use_vcr_cassette declaration tells VCR to record the responses of any HTTP requests in the cassette we give, in this case feed.

And now let’s get VCR in our cukes.

When /^I make an external call$/ do
VCR.use_cassette("feed", :record => :new_episodes) do
When 'I press "Create Feed"'
end
end

Because I am using a web step provided by capybara, I needed to create a new step definition that just delegated to the original step but wrapped the original step in the use_cassette block.

Other times, I was already using a custom step, so I simply added the use_cassette block to the step definition.

Given /^I have a feed I want to edit$/ do
VCR.use_cassette("feed", :record => :new_episodes) do
@feed = Factory :feed
end
end

VCR provides a Cucumber macro similar to the RSpec macro above, but I wasn’t able to get it working quickly and haven’t gone back to it. I know a coworker was able to use it correctly, so it’s definitely an issue of user error and not an issue with VCR.

Another nice feature in VCR is the ability to re-record the responses. This stops the recorded responses from getting stale over time and automatically does this on a defined interval.

You can set this up in the vcr.rb we created earlier. The change is bolded.

require 'vcr'

VCR.config do |c|
c.cassette_library_dir = 'fixtures/cassette_library'
c.stub_with :webmock
c.ignore_localhost = true
c.default_cassette_options = { :record => :none,
:re_record_interval => 7.days }
end

As you can see, we are adding re_record_interval to the default options. I set this interval to be 7 days since I don’t want the real requests to be run very often. And seven days is often enough that I will be able to respond quickly to changing responses.

Check out the webmock branch of lifeStreams on Github to see how I add WebMock and VCR. The first relevant commit is “start with webmock

Using WebMock and VCR has made testing the 3rd-party APIs I’m using in lifeStreams much easier and is a great alternative to hand-rolling stubs for the API responses. Take a look at their projects the next time you need to test external resources.

 

Rss-icon Rss-icon-over
Archive

Archive