简体   繁体   English

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

[英]How to stub ApplicationController method in request spec

I am needing to stub the response of a current_user method in an Rspec/capybara request spec. 我需要在Rspec / capybara请求规范中存根current_user方法的响应。 The method is defined in ApplicationController and is using helper_method. 该方法在ApplicationController定义,并使用helper_method。 The method should simply return a user id. 该方法应该只返回一个用户ID。 Within the test, I'd like this method to return the same user id each time. 在测试中,我希望这种方法每次都返回相同的用户ID。

Alternatively, I could fix my problem by setting session[:user_id] in the spec (which is what current_user returns)... but that doesn't seem to work either. 或者,我可以通过在规范中设置session[:user_id]来修复我的问题(这是current_user返回的内容)......但是这似乎也不起作用。

Are either of these possible? 这些都可能吗?

Edit: 编辑:

Here is what I've got (it is not working. It just runs the normal current_user method). 这是我得到的(它不工作。它只运行正常的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

Also not working: 也不工作:

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

skalee seems to have provided the correct answer in the comment. skalee似乎在评论中提供了正确的答案。

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)

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


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

This works for me and gives me a @current_user variable to use in tests. 这对我@current_user并给我一个@current_user变量用于测试。

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}

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

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. 它会使方法无效,并在rspec的控制器实例上设置ivar,并使其可用于@campaign的测试。

For Rspec 3+ the new api is: 对于Rspec 3+,新api是:

For a controller test, nice and short: 对于控制器测试,好的和短的:

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

Or for all instances of ApplicationController: 或者对于ApplicationController的所有实例:

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

None of the provided responses worked for me. 所提供的回复都不适合我。 As in @matt-fordam's original post, I have a request spec, not a controller spec. 和@ matt-fordam的原始帖子一样,我有一个请求规范,而不是控制器规范。 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 我通过在视图中对方法进行存根来解决这个问题,如其他SO帖子所述

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM