
If you interact with any web-based service you need to mock your requests to properly test you program. In reality there are two ways of mocking your external requests:
- You save the response, for example using something like VCR, or
- You mock the request using something like Webmock API.
Save response using VCR
VCR is a really cool gem, it allows you to replay whatever HTTP interactions you had the first time you invoked it, the idea is to always have the same response no matter what, because you actually save the resulting response into a file, a cassette.
The configuration, in this case using webmock as the stubbing facility, is something like this,
VCR.configure do |config|
config.configure_rspec_metadata!
config.cassette_library_dir = File.expand_path(File.join('..', 'cassettes'),
__FILE__)
config.hook_into :webmock
end
Obviously your specific cassette_library_dir
depends on your context, but you get the idea.
In Rspec, to use it, you would do something like this:
describe '#some_method', vcr: { cassette_name: 'my_request' } do
it 'here I request whatever url I need to' do
# fun stuff
end
end
This spec will create a file my_request.yml
that will contain all the HTTP information requested the time it was executed, including the actual response, and it will use this same file to mock the HTTP objects required to run your tests, so it will always give you the same response.
Mock response using Webmock
In cases where you actually don’t have a predefined URL to request, because maybe your program handles responses differently depending on the response code, you would need to explicitly mock this request. For that you need to use webmock directly.
Enabling webmock in this case is a little bit more elaborated than using VCR, but still not that complicated. You would need to do three things:
1. Implement a Sinatra Application that handles the actual request
require 'sinatra/base'
class DummyApp < Sinatra::Base
get '/' do
'hello'
end
end
2. Configure RSpec to stub specific domains with that Sinatra application
RSpec.configure do |config|
config.include WebMock::API
config.before(:each) do
stub_request(:any, /mocked-domain.com/).to_rack(DummyApp)
end
end
3. Use that in your spec
describe '#some_method' do
it 'here I request mocked-domain.com/hello' do
# fun stuff
end
end
Conclusion
Knowing both ways to handle (and mock) external web services is extremely useful because it allows you to have deterministic results. Super useful when building programs around external web services.