author avatar

nitturu.baba

Thu Nov 14 2024

How to write tests for external APIs?

This can be achieved using the gem "webmock".

Using webmock we will similate the external API call and use mockdata as the response to the APIs.

step1: install the gem "webmock"
step2: add the following lines to rails helper.


require 'webmock/webmock_api.rb'

config.before(:each) do
    stub_request(:any, /domain_name/).to_rack(WebmockApi
end


step3: create mock data responses for the APIs inside fixtures folder in spec.

member_api_success.json


# spec/fixtures/member_api_success.json
[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john.doe@example.com",
    "phone": "123-456-7890",
    "membership_type": "Gold",
    "status": "active"
  },
  {
    "id": 2,
    "name": "Jane Smith",
    "email": "jane.smith@example.com",
    "phone": "987-654-3210",
    "membership_type": "Silver",
    "status": "inactive"
  }
]


step4: inside spec create webmock file. Inside webmock create webmock_api.rb file. In this file we will simulate the responses for the API using mock data we have created.


class WebmockApi
  SPEC_FIXTURES_PATH = 'spec/fixtures'.freeze
  MEMBERS_SUCCESS = File.read("#{SPEC_FIXTURES_PATH}/members_api_success.json").freeze
  POSTS_SUCCESS = File.read("#{SPEC_FIXTURES_PATH}/posts_api_success.json").freeze
  ERROR = File.read("#{SPEC_FIXTURES_PATH}/error.json").freeze

  def self.call(env)
    new.call(env)
  end

  def call(env)
    action = env['REQUEST_METHOD']
    path = env['PATH_INFO']
    params = env['QUERY_STRING']

    case path
    when '/external_members_api_path'
      params.include?('test_user') ? [ 200, {}, [ MEMBERS_SUCCESS ] ] : [ 500, {}, [ ERROR ] ]
    when '/external_post_api_path'
      params.include?('new_post') ? [ 200, {}, [ POSTS_SUCCESS ] ] : [ 500, {}, [ ERROR ] ]
    end
  end
end


step5: write the test cases for the APIs in requests folder.


require 'rails_helper'
require 'webmock/rspec'

RSpec.describe "Members", type: :request do
  describe "GET /members_search_path" do
    context "when the members API call is successful" do
      it "returns member details from the API" do
        get "/external_members_api_path", params: { member: "test_user" }

        expect(response).to have_http_status(:ok)
        user = response.parsed_body["member"]
        expect(["id"]).to eq("123456")
        expect(user["name"]).to eq("abc")
      end
    end
    
    context "when the members API call is successful" do
      it "returns error message from the API" do
        get "/external_members_api_path", params: { member: "unknown_user" }

        expect(response).to have_http_status(:ok)
        expect(response).to have_http_status(:internal_server_error)
        error = response.parsed_body["error"]
        expect(error).to eq("Something went wrong")
      end
    end
  end
end


#ruby on rails