Mocking Third Party API’s

Everyone uses third party APIs in their project. These are the external services which allows you to access third party functionalities within the project without rebuilding them.

While writing test cases for any project it is very difficult to be sure that the test suites always run successfully as it is dependent on the third party API response. Hence, for handling such scenarios one has to mock third party APIs to be sure that our test cases does not hit any actual third party API service and that it runs in isolation.

Mocking third party API is just recording the response of the third party API call.

REASONS TO MOCK THIRD PARTY API.

One should prefer to mock third party APIs in order to avoid failure of test case arising due to issues at third party API end. The reasons for same may include:

  • Connectivity issues.

IMPLEMENTATION

Let’s add rspec-rails gem to the Gemfile under the applicable group.

group :development, :test do
gem 'rspec-rails', '~> 4.1.0'
end

Let’s write one test case which will run successfully assuming a good connectivity and a successful response from https://www.facebook.com/.

require "spec_helper'
require "net/http"
RSpec.describe "Stubbing external services" do
it "Should get response from facebook" do
uri = URI("https://www.facebook.com/")
response = Net::HTTP.get(uri)
expect(response).to be_an_instance_of(String)
end
end

In this case , actual response received from third party API will be compared.But if there is any server or connectivity issue while running the test cases , one will receive below mentioned error message.

F
Failures:
1) Stubbing external services Should get response from facebook
Failure/Error: response = Net::HTTP.get(uri)

SocketError:
Failed to open TCP connection to www.facebook.com:443 (getaddrinfo: Temporary failure in name resolution)
# ./spec/stub_request_spec.rb:22:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# SocketError:
# getaddrinfo: Temporary failure in name resolution
# ./spec/stub_request_spec.rb:22:in `block (2 levels) in <top (required)>'

Prominent solution to resolve this issue is to stub(mock) the used third party API request in order to avoid direct dependency on them.

Introducing webmock gem to stub the third party external services.

Let’s start by adding webmock gem to the gemfile under applicable group.

group :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '>= 2.15'
gem 'selenium-webdriver'
# Easy installation and use of web drivers to run system tests with browsers
gem 'webdrivers'
gem 'webmock'
end

BLOCK THIRD PARTY API CALLING.

To block calling third party API , we need to add some configurations, let’s disable external request by configuring the spec_helper.rb

require 'webmock/rspec'
RSpec.configure do |config|
WebMock.disable_net_connect!(allow_localhost: true)
# rest of predefined file content
end

Now let’s run the test cases again and see what happens!

rspec spec/stub_request_spec.rb 
F
Failures:
1) Stubbing external services Should get response from facebook
Failure/Error: response = Net::HTTP.get(uri)

WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: GET https://www.facebook.com/ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Host'=>'www.facebook.com', 'User-Agent'=>'Ruby'}

You can stub this request with the following snippet:

stub_request(:get, "https://www.facebook.com/").
with(
headers: {
'Accept'=>'*/*',
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'Host'=>'www.facebook.com',
'User-Agent'=>'Ruby'
}).
to_return(status: 200, body: "", headers: {})

============================================================
Finished in 0.00375 seconds (files took 0.2682 seconds to load)
1 example, 1 failure

Let’s stub the request and see the output again.

require "spec_helper"
require "net/http"
RSpec.describe 'Stubbing external services' do

before(:each) do
stub_request(:get, "https://www.facebook.com/").
with(
headers: {
'Accept'=>'*/*',
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'Host'=>'www.facebook.com',
'User-Agent'=>'Ruby'
}).
to_return(status: 200, body: "success", headers: {})
end

it "Should get response from facebook" do
uri = URI("https://www.facebook.com/")
response = Net::HTTP.get(uri)
expect(response).to be_an_instance_of(String)
end
end

Advantages

The advantage of web mocking is that you can focus on implementing behaviour of the code instead of worrying about implementation of third party APIs.

Disadvantages

Its observed that mocking third party API’s can lack protection ,which means any changes in third party API response will not be compatible to catch it.

One possible solution to overcome this problem testing the code once a day manually by calling actual third party API’s and then rely on mock test suites thereafter.

Conclusion

I would recommend using webmock gem among others as it is easier to implement and understand. For more details refer here.

Thank You!! Happy Coding!!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store