Stub your external endpoints using WebMock

On one of my projects we integrate with 2 external data suppliers through their APIs. In today’s development world this is fairly common and quite easy to do in terms of the integration.

However, the tricky part is figuring out how to test this properly. Using RSpec it’s easy to test models by stubbing out the functions which call the external services. However, when we run our cucumber features we can’t simply stub a method call on a model.

Hello WebMock

WebMock allows you to stub out your external endpoints at the HTTP level. In other words, you stub the external service and response and then allow your application to perform the remote request normally. Within the scope of your application this is a real cucumber feature i.e. an integration test.

Here’s how we use it…

Add the following code to your features/support/env.rb file:

require 'webmock/rspec'
World(WebMock::API, WebMock::Matchers)

The final line tells WebMock to allow all requests to proceed to the network as expected. This is important because we are running cucumber features.

Next, in the relevant cucumber step we will specify the behaviour for WebMock.

Given /^the remote service will return a valid response$/ do
  stub_request(:any, 'http://localhost:4567').to_return do |request|
    body = CGI::unescape(request.body)
    code = body.match(/<CODE_NBR>(.*)<\/CODE_NBR>/)
    response ="#{RAILS_ROOT}/test/responses/#{code[1]}.xml")
    {:body => response, :status => 200}

By passing a block to the stub_request method we can make WebMock behave in a more dynamic way, without having to stub out each individual request. In this case, we search the request body for a known tag which contains a unique code. We use that code to return an expected XML response we have saved. That’s it! Our cucumber features call our external services and process the responses as expected.

What did we do before?

We previously had a Sinatra app which would return the same pre-rolled responses used above. The behaviour was essentially the same, but it was complicated and it made our cucumber steps harder to follow and debug. It also meant for each test run we had to kick off and tear down WEBrick processes to run Sinatra properly – ugh! It was very clever but the kind of thing you have to re-learn every time you look at it.

And now…

Our features are now much cleaner, a little faster, but most importantly, readable and maintainable.


One thought on “Stub your external endpoints using WebMock

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s