How to stub ApplicationController method in request spec

前端 未结 6 1457
难免孤独
难免孤独 2020-12-12 18:16

I am needing to stub the response of a current_user method in an Rspec/capybara request spec. The method is defined in ApplicationController and is

相关标签:
6条回答
  • 2020-12-12 18:28

    Here are a couple of examples of the basic form.

    controller.stub(:action_name).and_raise([some error])
    controller.stub(:action_name).and_return([some value])
    

    In your particular case, I believe the proper form would be:

    controller.stub(:current_user).and_return([your user object/id])
    

    Here's a full working example from a project I work on:

    describe PortalsController do
    
      it "if an ActionController::InvalidAuthenticityToken is raised the user should be redirected to login" do
        controller.stub(:index).and_raise(ActionController::InvalidAuthenticityToken)
        get :index
        flash[:notice].should eql("Your session has expired.")
        response.should redirect_to(portals_path)
      end
    
    end
    

    To explain my full example, basically what this does is verify that, when an ActionController::InvalidAuthenticityToken error is raised anywhere in the app, that a flash message appears, and the user is redirected to the portals_controller#index action. You can use these forms to stub out and return specific values, test an instance of a given error being raised, etc. There are several .stub(:action_name).and_[do_something_interesting]() methods available to you.


    Update (after you added your code): per my comment, change your code so it reads:

    require 'spec_helper'
    
    describe "Login" do
    
       before(:each) do
          @mock_controller = mock("ApplicationController") 
          @mock_controller.stub(:current_user).and_return(User.first)
       end
    
      it "logs in" do
        visit '/'
        page.should have_content("Hey there user!")
      end
    
    end
    
    0 讨论(0)
  • 2020-12-12 18:29

    For Rspec 3+ the new api is:

    For a controller test, nice and short:

    allow(controller).to receive(:current_user).and_return(@user)
    

    Or for all instances of ApplicationController:

    allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(@user)
    
    0 讨论(0)
  • 2020-12-12 18:34

    This works for me and gives me a @current_user variable to use in tests.

    I have a helper that looks like this:

    def bypass_authentication
      current_user = FactoryGirl.create(:user)
    
      ApplicationController.send(:alias_method, :old_current_user, :current_user)
      ApplicationController.send(:define_method, :current_user) do 
        current_user
      end
      @current_user = current_user
    end
    
    def restore_authentication
      ApplicationController.send(:alias_method, :current_user, :old_current_user)
    end
    

    And then in my request specs, I call:

    before(:each){bypass_authentication}
    after(:each){restore_authentication}
    
    0 讨论(0)
  • 2020-12-12 18:41

    skalee seems to have provided the correct answer in the comment.

    If the method you're trying to stub is an instance method (most likely) and not a class method then you need use:

    ApplicationController.any_instance.stub(:current_user)

    0 讨论(0)
  • For anyone else who happens to need to stub an application controller method that sets an ivar (and was stymied by endless wanking about why you shouldn't do that) here's a way that works, with the flavour of Rspec circa October 2013.

    before(:each) do
      campaign = Campaign.create!
      ApplicationController.any_instance.stub(:load_campaign_singleton)
      controller.instance_eval{@campaign = campaign}
      @campaign = campaign
    end
    

    it stubs the method to do nothing, and sets the ivar on rspec's controller instance, and makes it available to the test as @campaign.

    0 讨论(0)
  • 2020-12-12 18:45

    None of the provided responses worked for me. As in @matt-fordam's original post, I have a request spec, not a controller spec. The test just renders the view without launching a controller.

    I resolved this by stubbing the method on the view as described in this other SO post

    view.stub(:current_user).and_return(etc)
    
    0 讨论(0)
提交回复
热议问题