Authentification stub en spécification de requête

Lorsque vous écrivez une spécification de requête, comment définissez-vous les méthodes de sessions et / ou de contrôleurs de stub? J’essaie de supprimer l’authentification dans mes tests d’intégration – rspec / Demandes

Voici un exemple de test

require File.dirname(__FILE__) + '/../spec_helper' require File.dirname(__FILE__) + '/authentication_helpers' describe "Messages" do include AuthenticationHelpers describe "GET admin/messages" do before(:each) do @current_user = Factory :super_admin login(@current_user) end it "displays received messages" do sender = Factory :jonas direct_message = Message.new(:sender_id => sender.id, :subject => "Message system.", :content => "content", :receiver_ids => [@current_user.id]) direct_message.save get admin_messages_path response.body.should include(direct_message.subject) end end end 

L’assistant:

 module AuthenticationHelpers def login(user) session[:user_id] = user.id # session is nil #controller.stub!(:current_user).and_return(user) # controller is nil end end 

Et le ApplicationController qui gère l’authentification:

 class ApplicationController < ActionController::Base protect_from_forgery helper_method :current_user helper_method :logged_in? protected def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end def logged_in? !current_user.nil? end end 

Pourquoi n’est-il pas possible d’accéder à ces ressources?

 1) Messages GET admin/messages displays received messages Failure/Error: login(@current_user) NoMethodError: undefined method `session' for nil:NilClass # ./spec/requests/authentication_helpers.rb:3:in `login' # ./spec/requests/message_spec.rb:15:in `block (3 levels) in ' 

Une spécification de demande est une enveloppe mince autour d’ ActionDispatch::IntegrationTest , qui ne fonctionne pas comme les spécifications de contrôleur (qui enveloppent ActionController::TestCase ). Même s’il existe une méthode de session, je ne pense pas qu’elle soit prise en charge (c’est probablement le cas, car un module inclus pour d’autres utilitaires inclut également cette méthode).

Je vous recommande de vous connecter en publiant des messages sur les actions que vous utilisez pour authentifier les utilisateurs. Si vous définissez le mot de passe ‘password’ (par exemple) pour toutes les usines User, vous pouvez faire quelque chose comme ceci:

 def login (utilisateur)
   post login_path,: login => user.login,: password => 'password'
 fin

Note pour les utilisateurs de Devise …

BTW, la réponse de @David Chelimsky peut nécessiter quelques modifications si vous utilisez Devise . Ce que je fais dans mes tests d’intégration / de requêtes (grâce à ce post StackOverflow ):

 # file: spec/requests_helper.rb def login(user) post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password end 

FWIW, en portant mes tests Test :: Unit sur RSpec, je voulais pouvoir me connecter avec plusieurs sessions (de conception) dans mes spécifications de demande. Il a fallu creuser, mais ça a fonctionné pour moi. Utilisation de Rails 3.2.13 et RSpec 2.13.0.

 # file: spec/support/devise.rb module RequestHelpers def login(user) ActionController::IntegrationTest.new(self).open_session do |sess| u = users(user) sess.post '/users/sign_in', { user: { email: u.email, password: 'password' } } sess.flash[:alert].should be_nil sess.flash[:notice].should == 'Signed in successfully.' sess.response.code.should == '302' end end end include RequestHelpers 

Et…

 # spec/request/user_flows.rb require 'spec_helper' describe 'User flows' do fixtures :users it 'lets a user do stuff to another user' do karl = login :karl karl.get '/users' karl.response.code.should eq '200' karl.xhr :put, "/users/#{users(:bob).id}", id: users(:bob).id, "#{users(:bob).id}-is-funny" => 'true' karl.response.code.should eq '200' User.find(users(:bob).id).should be_funny bob = login :bob expect { bob.get '/users' }.to_not raise_exception bob.response.code.should eq '200' end end 

Edit : correction typo

Vous pourriez aussi facilement passer la session en revue.

 controller.session.stub(:[]).with(:user_id).and_return() 

Tous les opérateurs spéciaux Ruby sont en effet des méthodes. L’appel 1+1 est identique à 1.+(1) , ce qui signifie que + est simplement une méthode. De même, session[:user_id] est identique à l’appel de la méthode [] en session , en tant que session.[](:user_id)