RSpec: How to turn off partial double verification temporarily

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

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 About 2 years ago