Testing External API integrations in Rails

June 15, 2017 ~ 2 min read

When your Rails application depends on a lot of communication with external services and API's its important that these integrations are tested properly.

At the same time we dont want the test suite to be hitting the external API's when they are ran as this is not practical and will greatly increase the time it take for the tests to complete. Thankfully we can easily get around this though a process call 'stubbing' and utilising the WebMock ruby gem.

Adding WebMock for Stubbing external API Calls

WebMock works by listening in the background when the test suite is running and intercepting any requests that we have defined a stub request for, it will then return the mock response that we have defined. Mock responses are a copy of what a real world response would be like from the external API.

To get started you will first need to add webmock to your Gemfile and then add the following to the top of your /test/test_helper.rb file initialize WebMock and disable external HTTP/HTTPS request.

# /test/test_helper.rb
require 'webmock/minitest'

WebMock.disable_net_connect!

Creating Mock Response Fixtures

Sometimes mock API responses can contain a large data payload which can quickly bloat out our ruby test classes, I prefer to store these mock responses as fixtures which keeps our code lean and also makes them reusable.

Lets create our first mock which is an access token response, this will live in a new directory called mocks that will be placed under /test/fixtures.

/* /test/fixtures/mocks/access_token_response.json */
{
  "access_token": "73bff7ffeda047ca892e54b289811011380b4bfabafff3bcb",
  "token_type": "bearer",
  "expires_in": 3599,
  "refresh_token": "dd8fbf83fa81bd21d384166de292959bc7ea388837a4e70a",
  "scope": "user",
  "created_at": 1495701071
}

So we can easily use any mocks that we have created lets also create a helper module that will give us access to them in our tests.

# /test/support/mock_fixtures.rb
module MockFixtures
  def mocks(filename)
    File.read(mocks_path_for(filename))
  end

  private

  def mocks_path_for(filename)
    File.join(File.dirname(__FILE__), '../fixtures/mocks/', filename)
  end
end

Now we have that added, we just need to tell the Rails test helper to load our helper module by adding the following to the top of the file..

# /test/test_helper.rb
require_relative './support/mock_fixtures'

Using WebMock in your tests

With all of the above setup you can now use WebMock in your tests, serving any of your mocks in response to and external API calls that you define a stub for.

# /test/controllers/oauth_controller_test.rb
require 'test_helper'

class OauthTokenTest < ActionDispatch::IntegrationTest
  setup do
    @token_url = 'https://example-oauth-api.com/auth/token'

    stub_request(:post, @token_url).to_return(
      status: 200,
      body: mocks('access_token_response.json'),
      headers: { 'Content-Type' => 'application/json' }
    )
  end  
end

That`s all there is to it really and now you can be at ease knowing that the the code you have wrote to interact with the external API is now fully tested.

Ben Barber

A software engineer specialising in the development of web applications using Elixir, Phoenix, Ruby on Rails and React. Find out more »

Join 423 other subscribers. No spam ever.