Вбиваємо зовнішні запити під час тестування rails додатків з допомогою VCR



Зовсім недавно, у мене виникла проблема полягає в тому, що тести мого додатка досить довго ходять. Це відбувається через те, що деякі частини коду люблять звертатися до сторонніх сервісів начебто iTunes і Facebook.

Звернення до сторонніх сервісів під час тестування це зло з наступних причин:

  1. Якщо під час виконання тестів починаються проблеми зі зв'язком, то вони можуть або проходити повільно, або зовсім падати.
  2. Як вже писалося — досить сильно сповільнюється швидкість проходження тестів.
  3. Можливі проблеми з обмеженням числа запитів самими сервісами.

На написання цієї статті мене надихнув пост How to Stub External Services in Tests, в якому описується кілька методик позбавлення від запитів до зовнішніх сервісів і підміна їх локальними викликами. У статті представлені наступні способи:

  1. Створити заглушку на сінатрі, яка піднімається на час ходіння тестів.
  2. Використовувати бібліотеку VCR, яка дозволяє перехоплювати всі зовнішні запити з відповідями і писати їх у файл.
З власного досвіду — обидва підходи гарні для кілька різних ситуацій. Сінатра хороша коли є один невеликий запит і відомий JSON відповіді. VCR хороша коли вже використовується чийсь SDK (в моєму випадку Koala для спілкування з Facebook) який робить ланцюжок запитів до чийогось апі використовуючи внутрішню логіку бібліотеки.

У цій статті ми зупинимося на використанні VCR. Для тестування використовувався rspec.

Для ясності варто відзначити, що файли з ланцюжком запитів (і їх вмістом) ідеології VCR називаються записами. Це можна помітити в назві методів і якщо подивитися документацію. Ну а сам ТЕЛЕФОН можна дослівно перекласти як «відік».

Першим ділом встановлюємо сам VCR і webmock для емуляції запитів у поза. Так само, webmock забороняє всі зовнішні запити під час тестів. Gemfile:

group :test do
...
gem 'webmock'
gem 'телефон'
...
end


Потім додаємо в spec_helper.rb:

require 'webmock/rspec'
require 'телефон'

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 секунд.

Повну документацію на бібліотеку можна подивитися тут.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.