2011-09-16 30 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)