At Agira, Technology Simplified, Innovation Delivered, and Empowering Business is what we are passionate about. We always strive to build solutions that boost your productivity.

, ,

RSPEC Stub To Test Real Third Party API’s

  • By Bharanidharan Arumugam
  • October 24, 2017
  • 959 Views

Introduction

Web applications that consume third-party APIs is a common part of web development. Applications like Facebook, GitHub, and many other OAuth providers are generally used for user signups. And sometimes we use Paypal or stripe and others for more complex purposes like payments. These third-party APIs are also consumed when we deal with service-oriented architecture in which many services are interconnected.

 

Writing test cases to the Third party API is commonly ignored by many developers because of the complexity it involves and many other issues. But let me explain you a real-time issue which I have faced by ignoring test cases for third-party APIs. We were developing a large scale FBX application which needed the use of Facebook API.

 

The scenario: Generally shopping sites like Amazon will have separate Facebook pages for each country. We were trying to run Geo-targeted ads for the UK but because of not writing the test cases for pagination the campaign matched with the wrong facebook page(US) and ads was shown for the wrong location.

 

So, even though there are some complexities involved in writing test cases for third-party APIs, it is mandatory that we write them to avoid the blunders happening. In this article, we will see how we are testing facebook graph API using the stub.

General reasons why we ignore to write the test case for 3rd party API?

Most of the time if we are consuming third-party API, we will ignore to write a test case for external API for the following reasons:

  • Connectivity issues can cause the tests to fail.
  • There might be a limit for the number of hits for that service and it might throw errors after that limit.
  • Authentication and access restrictions.
  • This may lead to slower response time and increase the payload.
  • Direct interaction with the API can have some side effects in the service
  • The Service might not have a sandbox or a staging server.
  • Using stubs and mocks for a third party API might become a tedious task, especially if the behavior is too complex or too many public API functions are used. Then mocking the client or stubbing its methods can lead to a lot of effort and maintenance work.

Importance and need of writing test cases for 3rd party API?

Example:

To explain the different ways on how to test an API we use the following example. We use a facebook client library(Koala) to request a list of fb user pages from an external service.

module UsersHelper
 include KoalaHelpers
 def fb_page_tokens_for_select(user)
   graph = Koala::Facebook::API.new(user.fb_graph_token)
   pages = Rails.cache.fetch("user_#{user.id}_pages", expires_in: 5.minutes) do
     Rhod.with_impatient_facebook(graph) do |fb|
       begin
         koala_read_pages(fb.get_connections('me','accounts'))
       rescue FeedUtils::FbApiException => e
         flash[:error] = "A Facebook error occured: #{e.message}"
       end
     end
   end
   return [["", user.fb_page_token]] if pages.blank?
   result = []
   pages.each do |page|
      if user.fb_page_id == page["id"]
         result = [["#{page["name"]} - (#{page["id"]})", page["access_token"]]].concat(result)
      else
         result = result.concat([["#{page["name"]} - (#{page["id"]})", page["access_token"]]])
      end
    end
    result
end
end

 

Below Koala helpers library handles FB graph request and response with pagination.

module KoalaHelpers
 def koala_read_pages(current_page)
pages = [current_page]
while current_page.next_page_params.present?
  current_page = current_page.next_page
  pages << current_page
end
pages.flatten
 end
end

 

WebMock

WebMock gem can also be used to stub the requests and responses, particularly the HTTP requests in ruby.

When using WebMock all other net connections except the localhost must be disabled.

# in spec_helper.rb
require 'webmock/rspec'
WebMock.disable_net_connect!(:allow_localhost => true)

 

This raises exceptions for all net connections, still allows communication via localhost and is a good way to find out what requests are sent to external services in our tests. An exception also provides details of how the specific request can be stubbed.

WebMock::NetConnectNotAllowedError:
[...]
You can stub this request with the following snippet:
stub_request(:get, "http://graph.facebook.com/v2.4/me/accounts").
   with(:headers => {
          'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
          'Content-Type'=>'application/json',
          'User-Agent'=>'Faraday v0.9.1'
        }).
   to_return(:status => 200, :body => "", :headers => {})

 

This stubs the HTTP request (type GET) for the URL http://graph.facebook.com/v2.4/me/accounts. Let’s stub the request in the test of our example.

require 'spec_helper'
require 'koala_helpers'
include KoalaHelpers
describe KoalaHelpers do
 before(:each) do
first_page = {
  "data" => ['data_1', 'data_2', 'data_3'],
  "paging" => paging
}
@api = Koala::Facebook::API.new("123")
@collection = Koala::Facebook::GraphCollection.new(first_page, @api)
 end
 describe "#next_page with next parameters" do
let(:paging){ {"next" => "http://graph.facebook.com/v2.4/me/accounts?a=2&b=3"} }
before(:each) do
  second_page = {
    "data" => ['data_4', 'data_5']
  }
  # Stub for koala#next_page call
  stub_request(:get, "https://graph.facebook.com/v2.4/me/accounts?a=2&access_token=123&b=3").with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Faraday v0.8.9'}).
    to_return(:status => 200, :body => {data: Koala::Facebook::GraphCollection.new(second_page, @api) }.to_json)
end
it "should return the next page of results" do
  result = koala_read_pages(@collection)
  expect(result).not_to be_empty
  expect(result.count).to  eq(5)
end
 end
 describe "#without next page parameters" do
let(:paging){ {:next => '' } }
it "should return the without next page of results" do
  result = koala_read_pages(@collection)
  expect(result).not_to be_empty
  expect(result.count).to  eq(3)
end
 end
end

 

VCR

Recording the live interaction and replaying the interactions during the tests can also be done to prevent any external requests. Using VCR gem we can record the test suites outgoing HTTP requests which can be replayed in future test runs. But for this, the external service should be available for the first test run.

Conclusion

So as discussed earlier despite many difficulties or issues that occur it is mandatory to write test cases for third-party APIs. You can decide the way you test the API depending on the context of the service. To read more on web application development follow Agira Technologies

Bharanidharan Arumugam

Technical Architect | Tech Lead | Mentor | - An enthusiastic & vibrant Full stack developer has 7 plus years of experience in Web development arena. Owns legitimate knowledge in Ruby, Ruby On Rails, AngularJs, NodeJs, MEAN Stack, CMS Services. Apart all, A Modest human who strictly says "No To Harming Humans".