Testing External API integrations in Rails
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.
Enjoyed This Post?
Other Posts You May Like