Stubbing External Web Requests in RSpec Testing with VCR

Remember VCRs?

Well, they're for more than just watching The Land Before Time a million times

you should watch The Land Before Time a million times

VCR is also an amazing Ruby gem that records your test suite's HTTP interactions and replays them during future test runs.

Why Use VCR?

Testing features that rely on external web requests, such as API calls, can be time consuming and expensive. Not only do such calls slow down the test run time, they have use up API calls, causing you to hit your rate limit much faster. This has the potential to, at best, force you to pause in your testing and resume later and, at worst, break a feature of your app temporarily.

So, how can we test our app's ability to, let's say, authorize a user with Twitter and preform actions like retrieve a user's friends or most recent tweets?

There are a number of ways in which we can "stub" or replace external web requests in our test suite. To learn more about them, you can read this awesome ThoughtBot article. Here, we'll be focusing specifically on using VCR to solve this problem.

How does VCR Work?

Once you configure VCR and set up your test suite to utilize it (more on that in a minute), you run your test suite. The first time the tests run, they will send external web requests. Those requests, and their response will be recorded on a "cassette", i.e. a file in your spec directory. Then, every subsequent time you run your test suite, VCR, with the help of the WebMock gem, will stub out the external web requests and instead re-play the cassette.

Setting Up VCR

1 . Add the VCR gem and the WebMock gem to your Gemfile and bundle install

gem 'webmock'  
gem 'vcr'  

2 . Configure VCR:

  • Create a folder support inside your spec folder. Create a file, vcr_setup.rb inside of spec/support. Fill it out with the following code:
VCR.configure do |c|  
  #the directory where your cassettes will be saved
  c.cassette_library_dir = 'spec/vcr'
  # your HTTP request service. 
  c.hook_into :webmock
end  

3 . Set up WebMock:

  • In your spec_helper file, add the following lines:
require 'webmock/rspec'  
WebMock.disable_net_connect!(allow_localhost: true)  

WebMock is a gem that stubs out the external web requests. VCR uses WebMock to prevent external web requests. VCR instead directs those requests to the cassettes.

4 . Write your tests using VCR. For the purposes of this example, we'll be testing our TwitterApi class. The TwitterApi class initializes to configure the client, using the Twitter gem. Here, we'll take a look at a test for the find_user_for method, which should take in an argument of a username and return the appropriate Twitter User object:

describe TwitterApi do  
  let(:client) {TwitterApi.new}

  describe "#find_user_for" do 
    it "given a username, it returns the correct user object" do 
      VCR.use_cassette('twitter/find_user_for') do
        user = client.find_user_for("sm_debenedetto")
        expect(user.class).to eq(Twitter::User)
        expect(user.username).to eq("sm_debenedetto") 
      end
    end
  end

Let's take a closer look at at the it block which utilizes VCR:

  • First, we tell VCR to record the "cassette" (the request to and response from the Twitter API), to a file spec/vcr/twitter/find_user_for.
  • Then, we proceed with our usual RSpec test. Next time the test suite runs, VCR will use WebMock to take over the web request and utilize the data in the cassette file.

And we're done! You're ready to stub out web requests in your test suites with ease.

subscribe and never miss a post!

Blog Logo

Sophie DeBenedetto

comments powered by Disqus
comments powered by Disqus