Как тестировать код, работающий с внешним АПИ. Заглушка на Синатре
Ситуация: в приложении вы опираетесь на внешний сервис для списаний с пластиковых карт. У сервиса крошечный АПИ: получить номер-маску карты по идентификатору пользователя, списать с указанного пользователя X рублей. Как проверить код, работающий с этим АПИ?
Конечно, можно не париться и реально дергать в тестах внешний сервис. Но это не круто. Во-первых, такие тесты будут тормозить. Во-вторых, такие тесты будут «мигать»: пропала сеть на мгновение, тест упал. В-третьих, это не всегда возможно: внешний сервис может не иметь песочницы или ограничивать количество запросов к ней.
Лучше в таких случаях использовать заглушки для внешних сервисов. Я использую четыре варианта заглушек, выбирая в зависимости от внешнего сервиса: свой или чужой, стабильный или часто меняющийся.
Один из вариантов — фейковый сервис на Синатре. Например, такой:
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
В коде выше два интересных момента. Во-первых, Class.new
с родителем Sinatra::Base
в let
, чтобы не добавлять глобальную константу из теста. Во-вторых, stub_request
Вебмока, который роутит все запросы в rack-приложение.
Советую использовать заглушки на Синатре в случаях, когда нужно застабить внешний сервис, у которого нет собственных заглушек (например, stripe-ruby-mock), а сделать заглушку-адаптер не получается.
P. S. Ещё больше постов о программировании, тестах и культуре разработки у меня в Телеграме.