Comment détourner la méthode ApplicationController dans les spécifications de la requête

J’ai besoin de modifier la réponse d’une méthode current_user dans une spécification de requête Rspec / capybara. La méthode est définie dans ApplicationController et utilise helper_method. La méthode doit simplement renvoyer un identifiant d’utilisateur. Dans le test, j’aimerais que cette méthode renvoie le même identifiant d’utilisateur à chaque fois.

Sinon, je pourrais résoudre mon problème en définissant session[:user_id] dans la spécification (ce que retourne current_user ) … mais cela ne semble pas fonctionner non plus.

Est-ce que l’un ou l’autre est possible?

Modifier:

Voici ce que j’ai (il ne fonctionne pas. Il ne fait que lancer la méthode 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 

Aussi ne fonctionne pas:

 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 semble avoir fourni la bonne réponse dans le commentaire.

Si la méthode que vous essayez de remplacer est une méthode d’instance (très probable) et non une méthode de classe, vous devez utiliser:

ApplicationController.any_instance.stub(:current_user)

Voici quelques exemples de la forme de base.

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

Dans votre cas particulier, je crois que la forme appropriée serait:

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

Voici un exemple concret d’un projet sur lequel je travaille:

 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 

Pour expliquer mon exemple complet, il ActionController::InvalidAuthenticityToken vérifier que, lorsqu’une erreur ActionController::InvalidAuthenticityToken est ActionController::InvalidAuthenticityToken dans l’application, un message flash apparaît et l’utilisateur est redirigé vers l’action portals_controller#index . Vous pouvez utiliser ces formulaires pour extraire et renvoyer des valeurs spécifiques, tester une instance d’une erreur donnée, etc. Vous .stub(:action_name).and_[do_something_interesting]() plusieurs .stub(:action_name).and_[do_something_interesting]() .


Mise à jour (après avoir ajouté votre code): par mon commentaire, modifiez votre code pour qu’il se lise comme suit:

 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 

Cela fonctionne pour moi et me donne une variable @current_user à utiliser dans les tests.

J’ai un assistant qui ressemble à ceci:

 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 

Et puis dans mes spécifications de demande, j’appelle:

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

Pour tous ceux qui ont besoin de modifier une méthode de contrôleur d’application qui définit un ivar (et qui est empêché de se demander pourquoi vous ne devriez pas le faire), voici un moyen qui fonctionne, avec la saveur de Rspec vers octobre 2013.

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

Il stubs la méthode pour ne rien faire et définit ivar sur l’instance de contrôleur de rspec, et la met à disposition pour le test en tant que @campaign.

Aucune des réponses fournies n’a fonctionné pour moi. Comme dans le post original de @ matt-fordam, j’ai une spécification de demande, pas une spécification de contrôleur. Le test ne fait que rendre la vue sans lancer de contrôleur.

J’ai résolu ce problème en écrasant la méthode sur la vue comme décrit dans cet autre article de SO

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

Pour Rspec 3+, la nouvelle API est:

Pour un test de contrôleur, agréable et court:

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

Ou pour toutes les instances de ApplicationController:

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