Skip to content

Instantly share code, notes, and snippets.

@stevenyap
Last active December 19, 2022 18:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenyap/ece6f92e6e49005a3cf4 to your computer and use it in GitHub Desktop.
Save stevenyap/ece6f92e6e49005a3cf4 to your computer and use it in GitHub Desktop.
Optimizing time-sensitive and HTTP-based test case using VCR and Timecop

Problem

You need to get the last hour data from an API but your test case runs too slow with the connections to API or test cases fail consistently with VCR due to different HTTP request sent in the params.

For example, expect(api.latest_data_time).eq 1.hour.ago in which 1.hour.ago will be different each time you execute the test case and the api http request param of the time will also change according to the current system time like http://api.com?starting_time=<new_current_time>

Solution

We need VCR to record the HTTP request and we use Timecop to freeze the system so that the HTTP request remains the same.

Refer: https://relishapp.com/vcr/vcr/docs/cassettes/freezing-time

Example Rspec

RSpec.describe SomeClass, vcr: true do
   describe '#last_candle' do
     it 'gets the last hour candle' do
        VCR.use_cassette('SomeClass/gets_last_hour_candle') do |cassette|
          Timecop.freeze(cassette.originally_recorded_at || Time.now) do
            last_candle_datetime = 1.hour.ago.change(min: 0)
            expect(strategy.last_candle.date_time).to eq last_candle_datetime
        end
      end
    end
end

Extract to RSpec Config with rspec metadata

If you have a lot of time-sensitive http-based test cases, you can extract it like below:

# spec_helper.rb
require 'webmock/rspec'
require 'vcr'
require 'timecop'

# VCR configure must be above RSpec.configure
# so that Timecop's RSpec hooks comes after VCR's RSpec hooks
VCR.configure do |c|
  c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
  c.hook_into :webmock
  c.configure_rspec_metadata!
end

RSpec.configure do |config|
  config.before(:example, freeze_current_time: true) do |_|
    Timecop.freeze(VCR.current_cassette.originally_recorded_at || Time.now)
  end

  config.after(:example, freeze_current_time: true) do |_|
    Timecop.return
  end
end

# test case
RSpec.describe SomeClass, vcr: true do
  describe '#last_candle' do
    it 'gets the last hour candle', freeze_current_time: true do
      last_candle_datetime = 1.hour.ago.change(min: 0)
      expect(strategy.last_candle.date_time).to eq last_candle_datetime
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment