Mock HTTP using VCR with RSpec | Mock Authy | Rails

Well, slower test suite is a nightmare both in your local machine and in your CI server. If your gem provider has built some Mocking APIs then its cool. But, no mocking API and you are writing Unit Test for your models and controller then beware, do not leave your app making HTTP requests everytime.

What to do?

If you cannot mock your library then mock the damn Internet. Simple enough! you can get going in a couple of minutes.

You are right! we will be using VCR to record the HTTP responses and replay the recordings using Webmock. You can use any other tools like


# in Gemfile
group :test do
  gem 'webmock'
  gem 'vcr'
# spec/support/vcr_config.rb
VCR.configure do |c|
  # This directory will hold all of your recordings
  c.cassette_library_dir = 'spec/vcr'

  # Your HTTP request service. You can also use fakeweb, webmock, and more
  c.hook_into :webmock

How to use?

VCR.use_cassette('cassette_group/cassette_name') do
   # the body of the test would go here...


it 'should auto update the authy_id just after phone_number is updated' do
  old_authy_id = user.authy_id
  VCR.use_cassette('models/users/authy_id') do
    user.update(first_name: 'New updated name', phone_number: '3779345998')
  expect(user.reload.authy_id).not_to eq(old_authy_id)

When you first time run this example, you see this new folder structure models/users/authy_id.yml  generated inside spec/vcr directory.

Mocking Authy

In my case I have set a after_save callback like

# In models/user.rb
after_save :update_authy_id, if: ->{phone_number_changed? || country_code_changed?}


def update_authy_id
  authy = Authy::API.register_user(
      email:        email,
      cellphone:    phone_number,
      country_code: country_code
  self.update(authy_id: if authy.present?

In that case, I needed to wrap all my create(:factory) calls with in VCR block. like

let(:user) do
  VCR.use_cassette('models/users/authy_id') do


If you are using Faker like gems to generate random data which are going to be used in HTTP parameters then you should skip. Like


# In factory
phone_number { Faker::PhoneNumber.cell_phone }

Use this if possible.

country_code { ['1', '977', '61'].sample }
phone_number { ['9X4X433445','2322334454'].sample }

Reason: In former implementation, there were thousands of possible outcome and I can guarantee that it’s not possible to record every combination by VCR. In later one, there are only two combinations and they can easily be recorded.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s