Geo-location integration is common today for every web application. We have gems on hand, to integrate Geo-location to our application. With few steps of configuration we can Geo-code our attributes ie., user addresses. But testing Geo-coding integration takes much more time than development! We currently use Google Map APIs for our work. If there are a lot of test cases, and if each test case made a Geo-location call, then we quickly cross the API threshold limit. It also takes more time to execute the test suite. It’s better to stub Geo-location calls so that we don’t need to bother with API limit and execution time.
To stub the call I am using Webmock gem which is used to stub HTTP requests. To know more about Webmock gem go through this link. For better understanding here I am going to explain this with a demo project. First clone the project from here and set up in your machine.
The main aim of the demo is Geo-code user address and displays latitude and longitude. To Geo-code the address I used ‘Geocoder’ gem. Here is the code to Geo-code an address:
#app/models/user.rb geocoded_by :full_address after_validation :geocode def full_address [street_address, city, state, zipcode ].join(', ') end
It calculates latitude and longitude of the address given by the user. To calculate, it calls the Google Map API and gets lat and long. So here we stub the call and return a predefined response that we already stored in our machine. To do that we have to do some webmock configuration. Here are the steps:
1) First download the response of the Geo-location using curl. We can find this in webmock documentation.
2) Place the response file under dir ‘spec/fixtures/webmock/maps.google.com/maps/api/geocode/’.
3) Configure the webmock as follows:
#spec/support/webmock.rb require 'pathname' require 'webmock/rspec' RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" dir = config.fixture_path + '/webmock' stubs = {} Dir["#{dir}/**/*"].each do |path| next if File.directory? path uri = path.dup uri.slice!( "#{dir}/" ) if File.basename(uri) == '_directory' uri = File.dirname(uri)+'/' end stubs["http://#{uri}"] = path end config.around(:each) do |example| stubs.each { |uri, path| WebMock::API.stub_request(:get, uri).to_return( File.new(path)) } WebMock.disable_net_connect!(:allow_localhost => true) example.call WebMock.allow_net_connect! end end
It’s restricts the HTTP requests which we are sending to external hosts except localhost. Whenever we made Geo-location call, instead of calling google API, webmock returns fixture file as a response. So we are getting lat and long without calling google API which is very interesting. Awesome, right? This also makes you test code execute very fast.
Note that WebMock disables all HTTP requests. To allow localhost, you need to specify :allow_localhost => true. Similary if you want to allow some other HTTP requests, say to Facebook, you can additionally pass :allow => [ ‘www.facebook.com’] too!
Do go through the example code repository and execute the specs in demo for better understanding.
I hope you now understand the advantages of stubbing external API requests.Any feedback or suggestion would be welcome.
Nice Blog.
This will help us testing Geo-loactions and also get to know more about Webmock ans Stubs
Do you know how to configure it with FactoryGirl?
Thank you!!