如何在请求规范中存根ApplicationController方法

时间:2011-09-16 18:36:31

标签: ruby-on-rails ruby rspec capybara

我需要在Rspec / capybara请求规范中存根current_user方法的响应。该方法在ApplicationController中定义,并使用helper_method。该方法应该只返回一个用户ID。在测试中,我希望这种方法每次都返回相同的用户ID。

或者,我可以通过在规范中设置session[:user_id]来修复我的问题(这是current_user返回的内容)......但这似乎也不起作用。

这些都可能吗?

编辑:

这是我得到的(它不起作用。它只运行正常的current_user方法)。

require 'spec_helper'

describe "Login" do

   before(:each) do
     ApplicationController.stub(:current_user).and_return(User.first)
   end

  it "logs in" do
    visit '/'
    page.should have_content("Hey there user!")
  end

end

也不行:

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

6 个答案:

答案 0 :(得分:57)

skalee似乎在评论中提供了正确的答案。

如果您尝试存根的方法是实例方法(最有可能)而不是类方法,那么您需要使用:

ApplicationController.any_instance.stub(:current_user)

答案 1 :(得分:14)

以下是基本表格的几个例子。

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

在您的特定情况下,我认为正确的形式是:

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

以下是我工作的项目的完整工作示例:

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

为了解释我的完整示例,基本上它的作用是验证当应用程序中的任何地方出现ActionController::InvalidAuthenticityToken错误时,会显示一条Flash消息,并且用户被重定向到portals_controller#index行动。您可以使用这些表单来存根并返回特定值,测试正在引发的给定错误的实例等。您可以使用多种.stub(:action_name).and_[do_something_interesting]()方法。


更新(在您添加代码之后):根据我的评论,更改您的代码,使其显示为:

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

答案 2 :(得分:3)

这对我有用,并为我提供了一个@current_user变量用于测试。

我有一个看起来像这样的帮手:

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

然后在我的请求规范中,我打电话给:

before(:each){bypass_authentication}
after(:each){restore_authentication}

答案 3 :(得分:2)

对于其他任何碰巧需要存根设置ivar的应用程序控制器方法的人(并且由于为什么你不应该这样做而无休止地讨厌)这里有一种方式可行,Rspec的味道大约在2013年10月。

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

它将方法存根为什么都不做,并在rspec的控制器实例上设置ivar,并使其可用于@campaign的测试。

答案 4 :(得分:1)

所提供的回复都不适合我。和@ matt-fordam的原始帖子一样,我有一个请求规范,而不是控制器规范。该测试只是在不启动控制器的情况下渲染视图。

我通过在other SO post

中描述的视图上的方法来解决这个问题
view.stub(:current_user).and_return(etc)

答案 5 :(得分:1)

对于Rspec 3+,新的api是:

对于控制器测试,很简短:

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

或者对于ApplicationController的所有实例:

allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(@user)