Read more

RSpec: How to turn off partial double verification temporarily

Emanuel
April 13, 2022Software engineer at makandra GmbH

While verifying doubles in RSpec is a good default, it is limited in the amount of methods it actually is able to verify.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

The background is that RSpec can't verify dynamically defined methods, which is a known issue Show archive.org snapshot for the usage of helper_method Show archive.org snapshot and also the reason why RSpec >= 3.6 Show archive.org snapshot (see "Mocks: without_partial_double_verification") added without_partial_double_verification.

This might be handy in case you are testing helpers in Rails, where you sometimes rely on methods defined in the application controller (e.g. current_user and current_power).

Example

class ApplicationController

  def current_user
    User.find_by(session[:user_id])
  end
  
  helper_method :current_user

end

module UsersHelper

  def user_display_name
    [current_user.first_name, current_user.last_name].join(' ')
  end

end

Unit test with error

describe UsersHelper do

  describe '#user_display_name' do
    it 'returns the first and last name of a user' do
      user = FactoryBot.create(:user)
      allow(helper).to receive(:current_user).and_return(user)
      
      expect(helper.user_display_name).to eq('Jim Knopf')
    end
  end

end

Error: <helper> does not implement: current_user

Solutions

RSpec >= 3.6 Unit test fixed with without_partial_double_verification

describe UsersHelper do

  describe '#user_display_name' do
    it 'returns the first and last name of a user' do
      user = FactoryBot.create(:user)
      
      without_partial_double_verification do
        allow(helper).to receive(:current_user).and_return(user)
      end
      
      expect(helper.user_display_name).to eq('Jim Knopf')
    end
  end

end

RSpec < 3.6 Unit test fixed by defining and using verify_doubles as a spec config

Another approach would be to define a spec config, which can be turned off and on for each spec.

describe UsersHelper do
  describe '#user_display_name', verify_doubles: false do
    it 'returns the first and last name of a user' do
      user = FactoryBot.create(:user)
      allow(helper).to receive(:current_user).and_return(user)
     
      expect(helper.user_display_name).to eq('Jim Knopf')
    end
  end
end

# In spec_helper.rb
RSpec.configure do |config|
  config.around(:each, verify_doubles: false) do |example|
    config.mock_with :rspec do |mocks|
      mocks.verify_partial_doubles = false
      example.run
      mocks.verify_partial_doubles = true
    end
  end
end

Note: This is just one over multiple options to solve the problem. You might also extract controller methods to helpers or pass in required objects as arguments.

Emanuel
April 13, 2022Software engineer at makandra GmbH
Posted by Emanuel to makandra dev (2022-04-13 09:19)