While working with web development we often use external services in applications for making the application features rich, interactive and easy to use for users. But testing these external services is challenging at times. RSpec and VCR can help developers to test such interactions with external services effectively and confidently.
Testing External Services
It is important to test the external services to ensure following - Verify the flow the process is working properly - Prevents regression testing while there is change in external APIs - End to end testing and identify the issues in early development phase
What is VCR?
VCR is a Ruby gem for HTTP interactions and replay them during future test runs. It interacts with HTTP servers for the first time, captures it and replay it during future test runs for fast and accurate result. The use of VCR provides following benefits: - Avoid disruptions caused by external service outages - Speed up the testing - Achieve consistency in Testing
Setup and Configuration for RSpec and VCR
Step 1: Add necessary gems Add following in gemfile to install rspec and vcr.
ruby
# Gemfile
group :test do
gem 'rspec-rails'
gem 'vcr'
gem 'webmock'
end
Run bundle install
to install the gems. Webmock
gem is used by VCR for the HTTP request mock.
Step 2: Configure RSpec and VCR
Execute rails generate rspec:install
to generate the configuration file for RSpec. It will create spec/spec_helper.rb
. Update spec/spec_helper.rb
with following config to configure VCR.
ruby
# spec/spec_helper.rb
require 'vcr'
VCR.configure do |config|
config.cassette_library_dir = 'spec/cassettes'
config.hook_into :webmock
end
RSpec.configure do |config|
config.before(:suite) do
VCR.turn_on!
end
config.after(:suite) do
VCR.turn_off!
end
end
Example
Let’s go through weather API integration and test coverage for it.
Step 1: Create the Weather Service Class
Create a WeatherService class in app/services/weather_service.rb
with following code:
ruby
# app/services/weather_service.rb
require 'net/http'
require 'json'
class WeatherService
API_BASE_URL = 'https://api.weatherapi.com/v1/current.json'
API_KEY = 'api_key'
def initialize(city)
@uri = URI(API_BASE_URL)
@uri.query = URI.encode_www_form(key: API_KEY, q: city)
end
def current_temperature
response = fetch_weather_data
data = JSON.parse(response.body)
data['current']['temp_c']
end
private
def fetch_weather_data
Net::HTTP.get_response(@uri)
end
end
Step 2: Write spec for WeatherService
Create a spec file at spec/services/weather_service_spec.rb
with following code:
ruby
# spec/services/weather_service_spec.rb
require 'rails_helper'
require 'weather_service'
RSpec.describe WeatherService, type: :service, vcr: true do
describe '#current_temperature' do
let(:city) { 'New York' }
subject(:current_temperatue) do
described_class.new(city).current_temperature
end
it 'fetches the current temperature using VCR' do
VCR.use_cassette('current_temperature') do
expect(temperature).to be_a(Float)
end
end
end
end
Step 3: Run the Test
Execute rspec spec/services/weather_service_spec.rb
to run the test.
VCR will record the HTTP interaction during the first run and use the recorded data for subsequent runs.
The VCR.use_cassette records HTTP interactions during the first test run and replays them in subsequent runs. The cassette name (‘current_temperature’) represents the name of the file where the recorded interactions are stored. You can find the cassette for the above test in spec/cassettes/current_temperature.yml
.
Conclusion
In this way we can leverage the advantage of VCR and RSpec to test the external service in an application. By isolating tests, speeding up test execution, and ensuring consistency, this combination provides developers with the confidence to build and maintain applications that interact seamlessly with external APIs or services. Happy Testing!!
Thanks for reading, no matter your software problem, we provide a complete solution to scope, design, develop, test, host, maintain and support it 24/7/365. Contact us to find out how can we bring your ideas to reality!