📜 ⬆️ ⬇️

Killing external requests while testing rails applications using VCR



More recently, I have a problem that my application tests run for quite a while. This happens because some parts of the code like to access third-party services like iTunes and Facebook.

Appealing to third-party services during testing is evil for the following reasons:
')
  1. If during the execution of tests, communication problems begin, they can either pass slowly or fall altogether.
  2. As it was already written, the speed of passing tests is rather slow.
  3. There may be problems with limiting the number of requests by the services themselves.


I was inspired to write this article by the post How to Stub External Services in Tests , which describes several techniques for getting rid of requests to external services and replacing them with local calls. The article presents the following methods:

  1. Create a cap on the Sinatra, which rises at the time of walking tests.
  2. Use the VCR library, which allows you to intercept all external requests with answers and write them to a file.

From my own experience - both approaches are good for several different situations. Sinatra is good when there is one small request and JSON response is known. A VCR is good when someone's SDK is already used (in my case, Koala to communicate with Facebook), which makes a chain of requests to someone's api using the library's internal logic.

In this article, we will focus on the use of VCR. For testing, rspec was used.

For clarity, it is worth noting that the files with a chain of requests (and their contents) in the VCR ideology are called cassettes. This can be seen in the name of the methods and if you look at the documentation. Well, the VCR itself can be literally translated as "Vidic".

First of all, we install the VCR itself and the webmock to emulate requests to the outside. Also, webmock prohibits all external requests during tests. Gemfile:

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


Then add to 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 


As an example, I will give a test of my API, which later makes several requests to Facebook.

In this file is a helper who registers a new test user and gives his last post from the tape.
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 


The spec / requests / facebook_register_post_request_spec.rb test file itself:

 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 


According to the experience of his small project, the speed of passing the tests decreased from 25 seconds (during an unstable connection could easily go in 1 minute) to 8 seconds.

Full documentation on the library can be found here .

Source: https://habr.com/ru/post/246409/


All Articles