Убиваем внешние запросы во время тестирования rails приложений с помощью VCR

в 18:24, , рубрики: rspec, ruby, ruby on rails, vcr, Веб-разработка, тестирование веб-приложений, Тестирование веб-сервисов

Убиваем внешние запросы во время тестирования rails приложений с помощью VCR - 1

Совсем недавно, у меня возникла проблема заключающаяся в том, что тесты моего приложения довольно долго ходят. Это происходит в виду того, что некоторые части кода любят обращаться к сторонним сервисам вроде iTunes и Facebook.

Обращение к сторонним сервисам во время тестирования это зло по следующим причинам:

  1. Eсли во время исполнения тестов начинаются проблемы со связью, то они могут либо медленно проходить, либо вовсе падать.
  2. Как уже и писалось — довольно сильно замедляется скорость прохождения тестов.
  3. Возможны проблемы с ограничением числа запросов самими сервисами.


На написание данной статьи меня вдохновил пост How to Stub External Services in Tests, в котором описывается несколько методик избавление от запросов к внешним сервисам и подмена их локальными вызовами. В статье представлены следующие способы:

  1. Создать заглушку на синатре, которая поднимается на время хождения тестов.
  2. Использовать библиотеку VCR, которая позволяет перехватывать все внешние запросы с ответами и писать их в файл.

По собственному опыту — оба подхода хороши для несколько разных ситуаций. Синатра хороша когда есть один небольшой запрос и известен JSON ответа. VCR хороша когда уже используется чей-то SDK (в моем случае Koala для общения с Facebook) который делает цепочку запросов к чьему-то апи используя внутреннюю логику библиотеки.

В этой статье, мы остановимся на использовании VCR. Для тестирования использовался rspec.

Для ясности стоит отметить, что файлы с цепочкой запросов (и их содержимым) в идеологии VCR называются кассетами. Это можно заметить в названии методов и если посмотреть документацию. Ну а сам VCR можно дословно перевести как «видик».

Первым делом устанавливаем сам VCR и webmock для эмуляции запросов во вне. Так же, webmock запрещает все внешние запросы во время тестов. Gemfile:

group :test do
  ...
  gem 'webmock'
  gem 'vcr'
  ...
end

Затем добавляем в spec_helper.rb:

require 'webmock/rspec'
require 'vcr'

VCR.configure do |c|
  c.cassette_library_dir = 'fixtures/vcr_cassettes' #указываем директорию где у нас будут лежать файлы с цепочками запросов
  c.ignore_hosts '127.0.0.1', 'localhost'
  c.hook_into :webmock
end

В качестве примера я приведу тест своего API, который в последствии делает несколько запросов к Facebook.

В этом файле лежит хелпер который регистрирует нового тестового пользователя и отдает его последний пост из ленты
spec/support/fb_helper.rb:

module FbHelper
  def init_test_user
    VCR.use_cassette('fb_test_user') do
      result ={}
      test_users = Koala::Facebook::TestUsers.new(:app_id => Rails.application.config.fb_app_id, :secret => Rails.application.config.fb_app_secret)
      sandra = test_users.list.select! { |x| x["id"]=="1462678604000503" }
      @sandra_token = sandra.first['access_token']
      @graph = Koala::Facebook::API.new(@sandra_token)
      @sender_id = @graph.get_object("me")["id"]
      posts = @graph.get_connections("me", "posts")
      @post_id = posts.select {|x| x['id']=="1462678604000503_1462707207330976"}.first["id"]
      result[:sandra_token] = @sandra_token
      result[:post_id]= @post_id
      result[:sender_id] = @sender_id

      return result
    end
  end
end

Сам файл с тестами spec/requests/facebook_register_post_request_spec.rb:

require 'spec_helper'

describe 'проверака шэринга постов в FB' do
  let(:device) {
    FactoryGirl.create(:device,:guid=>generate_guid)
  }
  it 'должен проходить с валидными токенами и постом' do
    result = init_test_user

    start_points = device.points

    VCR.use_cassette('fb_register_post') do #используем другой файл для чтения/записи запросов
      get register_fb_post_api_path,{:id=>device.guid,:post=>result[:post_id],:sender=>result[:sender_id],:token=>result[:sandra_token]}
    end
    expect(response).to be_success
  end
end

По опыту своего небольшого проекта, скорость прохождения тестов уменьшилась с 25 секунд (во время нестабильного коннекта могло спокойно уходить за 1 минуту) до 8 секунд.

Полную документацию на библиотеку можно посмотреть здесь.

Автор: r00t_aka_spin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js