it-swarm.cn

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

我需要在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
59
Matt Fordham

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

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

ApplicationController.any_instance.stub(:current_user)

57
fess .

以下是基本形式的几个例子。

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
14
jefflunt

这对我有用,并给我一个@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
iHiD

对于其他任何碰巧需要存根设置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的测试。

2
Michael Johnston

对于Rspec 3+,新api是:

对于控制器测试,Nice和short:

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

或者对于ApplicationController的所有实例:

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

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

我通过在视图中描述方法来解决这个问题,如此 其他SO post

view.stub(:current_user).and_return(etc)
1
jwadsack