Mocking API calls with Webmock

I have been working on calling and parsing data from the github API. In this case reading readme files from a users CV repository for a developer showcase. I want to test this code and this is how I stubbed out the API calls.

I wanted to stub out external requests for two key reasons:

  1. We had a limited number of calls to the API per hour (60)
  2. To speed up the testing.

For this I used the webmock gem after reading this helpful intro from thoughbot.

The first thing that Webmock provides is block all HTTP requests simply by its inclusion. Therefore it is important that it is added to the Gemfile in the test environment only. For the purpose of these tests we allowed localhost requests as there is no network overhead, in the spec_helper.rb is included.

    require ‘webmock/rspec’
    WebMock.disable_net_connect!(allow_localhost: true)

At this point the request are guaranteed blocked and any tests not effectively mocked will fail.

Next is to stub the responses for certain requests. Webmock provides a myriad of ways to stub requests. In this case using external files to provide the response content made most sense. This method allows a maximum separation of logic from content. It also means mocked responses can serve up a large amount of content without obscuring code. 

    stub_request(:get, <uri>).to_return(File.new(path/to/file.txt))

When using rspec this code should be used in a before block.

NB. Requests need to be stubbed in each test, a before(:all) block is insufficient.

Last is to generate the content in the response. This content can easily be created by hand if you are confident. In my experience so far I have to advise against it. The more obscure HTTP headers that you will neglect from a fabricated response may still have an effect. 

It is possible to use the terminal command curl to store an exact copy of a request from the api. This is done as follows.

    $ curl -is www.example.com > trial.txt

NB. The ’-i’ switch makes curl return the request headers and content.

We saved these files in the fixtures folder within the rspec folder. Finally for convenience we wrapped the functionality for generating this copied responses into a rake task. This was done as follows and it meant that the command rake git_stub would make all the requests to the github api once.

    task :git_stub do
      `curl -is https://api.github.com/users/CrowdHailer > trial.txt`
      `curl -is https://api.github.com/users/CrowdHailer/repos > trial2.txt`
    end

Benefits of this method are:-

  1. genuine response data to test models
  2. Not a single request needs to be made during test runs for maximum speed
  3. The disabling of net connections means no requests can get through accidentally
  4. Renewing the test data is as easy as possible with a single rake call

This method is not yet perfect. At the moment there is some code duplication to create stubs in rspec test and cucumber tests. I have found this article which demonstrates a similar procedure using the VCR gem. Any comments or improvements on this method are welcome