postnote

We currently have a full team here at Abletech but in saying that we're always on the look-out for great developers. If that sounds like you, feel free to get in touch.

postnote

News & Updates

Testing HTTP interactions in Rails using VCR

by cameronfowler.

If your Ruby on Rails application performs any HTTP requests to an external service, you will know they are a pain to test. The issue with these requests is that they are slow. Not only that, they are unreliable. Any self respecting programmer would do their best to avoid having live HTTP requests in their tests.

I previously have found myself creating some sort of XML file to represent the expected response from the request then stubbing out any real calls to just return this pre-made response. The concept is pretty simple, but is slow to set up, especially if you have a few different scenarios to test!

Introducing VCR, https://www.relishapp.com/myronmarston/vcr

VCR uses a similar concept, however it does all the hard work, leaving time to actually do testing, instead of wrangling XML or JSON fixtures. VCR is a ruby gem written by Myron Marston that records HTTP responses and saves them to files called ‘cassettes’. The cassettes are recorded the first time tests are run and saved to a corresponding file, similar to a fixture. These cassettes can be committed to source control, so other users wont even know they are there. Tests will just run as per usual. Great stuff.

Without further ado, here are the steps to get VCR working in an existing project.

Add VCR and fakeweb to the test environment in your Gemfile. Multiple HTTP stubbing libraries are supported; we are using fakeweb.

# Gemfile
group :test do
  gem "vcr", "~> 2.0.0.rc1"
  gem "fakeweb"
end

Run a 'bundle install'.

Next up we configure VCR in test/test_helper.rb

VCR.configure do |c|
  c.cassette_library_dir = 'test/vcr_cassettes'
  c.hook_into :fakeweb
end

When testing, the aim is to use VCR anywhere where there is a HTTP request. The first time the tests are run, VCR will store the response of the request in a file called a cassette. Every successive request will then use the saved response to simulate the actual response of the external tracking service.

Here is an example of VCR in use to test the TrackingApi model. Note that this test is using Shoulda, but VCR can be used in conjunction with the testing framework of your preference.

context "with a delivered package" do
  setup do
    @tracking_code = 'AB123456789YZ'
    VCR.use_cassette('delivered_parcel') do
      @msg, @code = TrackingApi.query(@tracking_code)
    end
  end
  should "have the correct code" do
    assert_equal TrackingApi::RETURN_CODE_FINISHED, @code
  end
end

In the above example, the TrackingApi.query method does a HTTP GET to an external API to check on the status of a parcel. The response is saved as 'test/vcr_cassettes/delivered_parcel.yml'.

It's that easy to get going and is configurable enough to be fit most situations.

There are two main benefits to using VCR to stub external requests:

  1. It's faster to setup and more realistic than manually stubbing out the requests manually.
  2. It is maintainable. If the response changes and the application breaks, just delete the saved cassettes. VCR will record new ones, and you can fix the issues until your tests pass again.

So, I've found VCR’s cassettes more useful than I ever found normal cassettes. It's a great gem that makes testing HTTP requests painless.