How to Mock HTTP External Services?

I’ve seen quite a few ways to mock external services (like stripe or some other 3rd party api) and I’m wondering which ones do you use in which situation? Here’s what I’ve found.

  • VCR - Records the response from a real web service call and then plays it back
  • capybara_discoball - You use this in the Learn app and for all of your external services. Seems like it could be a bit of an investment in time to build, but might allow you to control more results. I’m interested but only see 4 stars on github, so I’m not sure if it’s still being used
  • Shamrack - capybara_discoball references this in it’s Readme as an alternative.
  • Webmock - possibly with a sinatra app
  • Stubbing the client gem - I saw this in the “Geocoding on Rails” book where Josh wrote a FakeGeocoder class. One drawback to this seems that you don’t test the full stack including http parsing.

Please let me know what your current practices are for stubbing external services. A weekly iteration video on the topic would be even better :smile:.

I would say our most common setup is to first have Webmock installed disabling all external HTTP requests. That is in our default spec/spec_helper.rb.

For one or two simple requests, I’d say we most frequently just stub and spy on the request using Webmock and RSpec Mock’s test spies. Once we start relying on the external API more heavily, we’ll move to using a Sinatra-based fake as described in How to Stub External Services in Tests.

We typically don’t use a VCR-based approach, but Jared Carroll (thougthbot alumni!) wrote a good VCR-based article, How to Test External APIs.

Some considerations when choosing between Sinatra-based Fakes and VCR:

  • Sinatra allows more visibility and control but requires more code.
  • VCR fixtures are harder to control, because the service is live, but can be implemented quickly for a request.
  • Sinatra requires more maintenance when the API changes.
  • VCR requires more maintenance when your tests change.
  • Sinatra never talks to the live server, so there are risks of passing tests with broken code.
  • VCR allows you to re-record requests, so you can verify that the request will still work.
  • Sinatra can be combined with a rarely-run set of focused tests to ensure that the client still can communicate with the server between releases.
1 Like

Is something like VCR easy to record and use not just for testing but for a situation where you are offline and want to mock an api so you can code offline? Is that easy to implement with that?

That helps. Thanks.

@croaky, thanks for the breakdown of fake server vs. VCR. I have used VCR on a bunch of projects and like it, but there are some services that due to the nature of how they authenticate (such as S3) that are extremely difficult to use with VCR (there are some tickets on the VCR repo for the issues, but they are not likely to be resolved soon).

An approach I’ve started using to protect myself against external APIs changing but having my stubbed/recorded tests passing in test (as false positives) is to have the CI environment actually talk to an external server. This practice might not be possible for all external services, but since your CI environment is likely already network-enabled, it can be useful to be have that confirmation happen when you do your build.

Hey, @croaky… I tried your WebMock suggestion, but cannot find that gem available for jRuby so I’m going to take a look at the Sinatra approach. If you have any suggestions under jRuby, please let me know. Thanks.

UPDATE: Figured it out; configuration issue.