ruby-on-railsrubyrspecrspec-railsrspec-mocks

How to test a private controller method without using allow_any_instance_of?


Because of rubocop error I want to avoid using allow_any_instance_of in my specs.

I'm trying to change this one:

  before do
    allow_any_instance_of(ApplicationController).to receive(:maintenance_mode_active?).and_return(false)
  end

  it 'returns http success' do
    expect(response).to have_http_status(:success)
  end

According to the rubocop-docs it should be like:

  let(:maintenance_mode?) { instance_double(ApplicationController) }

  before do
    allow(ApplicationController).to receive(:maintenance_mode_active?).and_return(false)
    allow(maintenance_mode?).to receive(:maintenance_mode_active?)
  end

  it 'returns http success' do
    expect(response).to have_http_status(:success)
  end

Class which I want to test:

private

def check_maintenance?
  if maintenance_mode_active? == true
    redirect_to maintenance_mode
  elsif request.fullpath.include?(maintenance_mode_path)
    redirect_to :root
  end
end

def maintenance_mode_active?
  # do sth ...
  mode.active?
end

With code above I've got an error:

 2.1) Failure/Error: allow(ApplicationController).to receive(maintenance_mode?).and_return(false)
        #<InstanceDouble(ApplicationController) (anonymous)> received unexpected message :to_sym with (no args)
      # ./spec/controllers/static_pages_controller_spec.rb:15:in `block (4 levels) in <top (required)>'

 2.2) Failure/Error: allow(ApplicationController).to receive(maintenance_mode?).and_return(false)

      TypeError:
        [#<RSpec::Mocks::MockExpectationError: #<InstanceDouble(ApplicationController) (anonymous)> received unexpected message :to_sym with (no args)>] is not a symbol nor a string
      # ./spec/controllers/static_pages_controller_spec.rb:15:in `block (4 levels) in <top (required)>'

Solution

  • You must stub ApplicationController to return the instance_double(ApplicationController):

    let(:application_controller) { instance_double(ApplicationController) }
    
    allow(ApplicationController).to receive(:new).and_return(application_controller)
    allow(application_controller).to receive(:maintenance_mode_active?).and_return(false)