2011-09-16 103 views
55

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

或者,我可以通过在规范中设置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 
+13

是'current_user'一个类的方法描述磕碰的视图的方法去解决呢?我觉得不是。因此,您可能需要'ApplicationController.any_instance.stub(:current_user)'而不是'ApplicationController.stub(:current_user)'。 – skalee

回答

13

这里有两个基本形式的例子。

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 actio ñ。您可以使用这些表单来存根并返回特定值,测试引发的给定错误的实例等。有几种方法可供您使用。


更新(您添加代码后):

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

存根只是任何类中定义的任何方法的替代者。在你给的例子中,它是'ApplicationController'上定义的一个'current_user'方法,是否正确?除非我误解了你的问题,否则同样的基本形式应该起作用。你能发布你所写的测试的最佳形式,即使它不起作用吗? – jefflunt

+0

所以,我假设你的测试是在一个以'describe ApplicationController'开头的规范中,所以我的不好。如果情况并非如此,那么你应该仍然可以执行'ApplicationController.stub(:current_user).and_return([你的用户对象/ id])' – jefflunt

57

skalee似乎已经提供了注释的正确答案:按我的意见,所以它读取更改代码。

如果你想存根的方法是一个实例方法(最有可能),而不是一类的方法,那么你需要使用:

ApplicationController.any_instance.stub(:current_user)

+25

这仍然适用于Rspec 3,但会提供弃用警告。这是新的语法:'allow_any_instance_of(ApplicationController).to接收(:current_user)。and_return(your_test_user)' – Sharagoz

+1

喜欢这个引用 - “使用此功能通常是一种设计气味” - 来自[Rspec docs](https://github.com/rspec/rspec-mocks)。 – brntsllvn

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} 
2

对于谁比谁碰巧需要存根的应用程序控制器的方法设置了一个伊娃(并且被无尽的关于为什么你不应该这样做)的这种方式是有效的,这与大约在2013年10月的Rspec的味道有关。

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

它将该方法存根无用,并在rspec的控制器实例上设置ivar,并将其作为@campaign提供给测试。

+0

工具迟到以结束无尽的流浪,但仅仅是为了防止我把电脑扔出窗外。谢谢! – eggmatters

1

没有提供的响应为我工作。正如在@ matt-fordam的原文中,我有一个请求规范,而不是控制器规范。测试只是渲染视图而不启动控制器。

我通过在本other SO post

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