Rails, authentification reposante & amp; RSpec - Comment tester de nouveaux modèles nécessitant une authentification
-
09-06-2019 - |
Question
J'ai créé une application d'apprentissage utilisant Bort . , qui est une application de base incluant l’authentification reposante et RSpec. Je l'ai mis en marche et j'ai ajouté un nouvel objet qui nécessite que les utilisateurs soient connectés avant de pouvoir faire quoi que ce soit ( before_filter: login_required
dans le contrôleur). [edit: Je devrais également mentionner que l'utilisateur has_many
de la nouvelle classe et que seul l'utilisateur devrait pouvoir le voir.]
J'ai créé le nouveau modèle / contrôleur en utilisant les générateurs de Rspec qui ont créé un certain nombre de tests par défaut. Ils passent tous s’il n’ya pas de before_filter
mais que plusieurs échouent, comme on pouvait s’y attendre, une fois que before_filter
est en place.
Comment puis-je faire en sorte que les tests générés s’exécutent comme s’il y a / n’est pas un utilisateur connecté? Ai-je besoin de tout un lot de correspondances non connectées - de tests de redirection? Je suppose que c’est une technique de moquage ou de montage, mais je suis novice en RSpec et un peu à la dérive. De bons liens au tutoriel RSpec seraient également appréciés.
La solution
J'ai une configuration très similaire. Vous trouverez ci-dessous le code que j'utilise actuellement pour tester ce matériel. Dans chacun des décris
, je mets:
it_should_behave_like "login-required object"
def attempt_access; do_post; end
Si vous avez uniquement besoin d'un identifiant ou
it_should_behave_like "ownership-required object"
def login_as_object_owner; login_as @product.user; end
def attempt_access; do_put; end
def successful_ownership_access
response.should redirect_to(product_url(@product))
end
Si vous avez besoin de propriété. De toute évidence, les méthodes d'assistance changent (très peu) à chaque tour, mais cela représente la plus grande partie du travail à votre place. Ceci est dans mon spec_helper.rb
shared_examples_for "login-required object" do
it "should not be able to access this without logging in" do
attempt_access
response.should_not be_success
respond_to do |format|
format.html { redirect_to(login_url) }
format.xml { response.status_code.should == 401 }
end
end
end
shared_examples_for "ownership-required object" do
it_should_behave_like "login-required object"
it "should not be able to access this without owning it" do
attempt_access
response.should_not be_success
respond_to do |format|
format.html { response.should be_redirect }
format.xml { response.status_code.should == 401 }
end
end
it "should be able to access this if you own it" do
login_as_object_owner
attempt_access
if respond_to?(:successful_ownership_access)
successful_ownership_access
else
response.should be_success
end
end
end
Autres conseils
Lorsque vous ne testez pas l'authentification mais les contrôleurs nécessitant l'authentification de l'utilisateur, je stub généralement la méthode de filtrage:
before(:each) do
controller.stub!(:authenticate).and_return(true)
end
L'exemple ci-dessus fonctionne où mon before_filter est défini sur la méthode d'authentification:
before_filter :authenticate
et l'authentification dans mon application utilise l'authentification de base HTTP, mais il peut s'agir de tout autre mécanisme d'authentification.
private
def authenticate
authenticate_or_request_with_http_basic do |user,password|
user == USER_NAME && password == PASSWORD
end
end
Je pense que c'est un moyen assez simple de tester.
J'ai trouvé quelques réponses à ma propre question. En gros, je devais comprendre comment simuler l'utilisateur de restful_authentication
afin que les tests du contrôleur rspec générés automatiquement puissent réussir, même si j'avais ajouté before_filter: login_required
. .
Voici quelques-unes de mes ressources récemment trouvées:
RSpec: ça devrait se comporter comme
rspec, restful_authentication, et login_required
utilisation de restful_authentication current_user dans les spécifications du contrôleur
Pour simuler un utilisateur connecté, je piraterai le contrôleur pour définir @ utilisateur_current
manuellement:
module AuthHelper
protected
def login_as(model, id_or_attributes = {})
attributes = id_or_attributes.is_a?(Fixnum) ? {:id => id} : id_or_attributes
@current_user = stub_model(model, attributes)
target = controller rescue template
target.instance_variable_set '@current_user', @current_user
if block_given?
yield
target.instance_variable_set '@current_user', nil
end
return @current_user
end
def login_as_user(id_or_attributes = {}, &block)
login_as(User, id_or_attributes, &block)
end
end