web-dev-qa-db-fra.com

Comment stub méthode ApplicationController dans la spécification de demande

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

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

Ces deux possibilités sont-elles possibles?

Modifier:

Voici ce que j'ai (cela ne fonctionne pas. Il exécute simplement la méthode courante 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

Ne fonctionne pas non plus:

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

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

ApplicationController.any_instance.stub(:current_user)

58
fess .

Voici quelques exemples du formulaire de base.

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

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

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

Voici un exemple de travail complet 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, essentiellement ce que cela fait est de vérifier que, lorsqu'une erreur ActionController::InvalidAuthenticityToken Est générée n'importe où dans l'application, qu'un message flash apparaît et que 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 en cours de levée, etc. Plusieurs méthodes .stub(:action_name).and_[do_something_interesting]() sont à votre disposition.


pdate (après avoir ajouté votre code): par mon commentaire, changez votre code pour qu'il se lise:

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

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

J'ai une aide 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}
3
iHiD

Pour toute autre personne qui a besoin de stub une méthode de contrôleur d'application qui définit un ivar (et qui a été contrecarrée par des branlettes sans fin sur les raisons pour lesquelles vous ne devriez pas le faire), voici une méthode 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 l'ivar sur l'instance de contrôleur de rspec, et le rend disponible pour le test en tant que @campaign.

2
Michael Johnston

Pour Rspec 3+, la nouvelle API est:

Pour un test de contrôleur, Nice et court:

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

Ou pour toutes les instances d'ApplicationController:

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

Aucune des réponses fournies n'a fonctionné pour moi. Comme dans le message d'origine de @ matt-fordam, j'ai une spécification de demande, pas une spécification de contrôleur. Le test rend simplement la vue sans lancer de contrôleur.

J'ai résolu cela en stubbing la méthode sur la vue comme décrit dans ce autre SO post

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