DEV Community

Vasily Polovnyov
Vasily Polovnyov

Posted on

How to test code that works with an external API: a stub on Sinatra

Imagine a situation: your application relies on an external service responsible for card charges. The service has a tiny API: get the card number (mask) by user ID, charge X dollars from the user. How do we test the code that works with this API?

Of course, you can actually request that external service in the tests. Maybe it even has a sandbox for such cases. But this solution is not so efficient. First of all, it slows down the tests: every request has a time cost. Secondly, it makes tests flaky: network issues will cause them to randomly fail. Thirdly, it's not always possible: the external service may have no sandbox or have strict request limits.

In such cases, it is better to use stubs for external services. I use four options of stubs, depending on the external service: is it my own or someone else's, stable or frequently changing?

One of the options is a fake service on Sinatra. Such as this one:

let(:fake_api) do
  Class.new Sinatra::Base do
    get "/users/:user_id/card" do
      content_type :json

      { number: "4111...1111" }.to_json
    end
  end
end

before do
  stub_request(:any, /api.nanocashier.com/).to_rack(fake_api)
end
Enter fullscreen mode Exit fullscreen mode

There are two interesting things in the above code. Firstly, Class.new with the Sinatra::Base parent in let, so you don't add a global constant from the test. Secondly, the stub_request of Webmock, which routes all requests to the rack application.

I use such rack-based stubs when I have to mock an external service which doesn't have its own stubs (e.g. stripe-ruby-mock) and making adapter-like stub is not possible.

Discussion (0)