Rester au sec tout en testant un contrôleur, autorisé par CanCan
-
27-09-2019 - |
Question
J'écris rétroactivement certains tests, en utilisant RSpec, pour un projet Rails.
J'utilise la pierre précieuse CanCan fournir une autorisation. J'ai décidé d'écrire une spécification qui permettra de tester le modèle ability.rb
.
Je suis ensuite allé à tester mes autres modèles.
Je suis passé aux contrôleurs, et j'ai rencontré un énorme problème: je teste mes capacités tout recommencer
En fait, je dois bouchonner une série de modèles et stub leurs associations; sinon la réponse retourne juste 403 Forbidden
.
La raison de cela, est que le contrôleur est essentiellement chargé de se soucier de l'autorisation.
Je ne suis pas tout à fait sûr où aller d'ici. J'écrasant jusqu'à 6 modèles, juste pour écrire un seul test.
I sais le travail des capacités, qui est ce que ability_spec.rb
est pour.
Donc, cette question est vraiment 2 fois:
- Dois-je me tester le modèle de capacité séparément?
- au cas où les tests de contrôleur sont concernés avec des autorisations appropriées?
Modifier require 'spec_helper' :: inclure TestHelpers # Concevoir pour donner votre accès spec aux aides
describe TokensController do
before(:each) do
@mock_user = User.new(:username => "bob", :email => "user@user.com", :password => "longpassword")
@mock_user.role = "admin"
sign_in @mock_user
#Ability.stub!('can').and_return(true)
end
it "should let me see grids/:g_id/tokens index" do
test_grid = mock_model(Grid)
test_token = mock_model(Token)
Grid.stub!(:find).and_return(test_grid)
Token.stub!(:find).and_return(test_token)
get 'index'
a1 = Ability.new(@mock_user)
a1.can?(:index, Token).should be_true # This line works fine; as it should
puts response.status #This returns 403, which means CanCan::AccessDenied was raised
end
end
Merci,
Robbie
La solution
Je testons séparément le modèle cancan, mais l'essai ce qu'il permettra dans quelles conditions.
Je pense que si vous faites des choses comme
authorize! :take_over, @the_world
Alors je pense que vous devriez tester que dans le contrôleur. Je ne suis pas sûr que vous devez tester les 6 versions de vos modèles cependant.
Vous pouvez bouchonner le Ability.can? classe et l'ont répondu vrai / faux, et tester la façon dont vos poignées de contrôleur quand il peut (et surtout) quand il ne peut pas continuer.
Autres conseils
Je ne sais pas si cela est trop tard pour vous, mais je couru dans le même problème, et résolu à l'aide de l'exemple de code suivant -
before do
@user = Factory.create(:user)
sign_in @user
@abilities = Ability.new(@user)
Ability.stub(:new).and_return(@abilities)
end
end
J'ai écrasa Capacité # nouveau, me donner une référence à l'instance de capacité qui contrôle l'utilisateur actuel. Ensuite, je peux bouchonner capacités spécifiques comme celle-ci:
@abilities.stub!(:can?).with(:destroy, regatta).and_return(true)
ou donner des privilèges d'administrateur:
@abilities.stub!(:can?).and_return(false)
Tout comme la réponse de Sam, mais à partir de la page wiki CanCan sur le test:
Test Controller
Si vous voulez la fonctionnalité d'autorisation d'essai au niveau du contrôleur une option consiste à vous identifier l'utilisateur qui dispose des autorisations appropriées.
user = User.create!(:admin => true) # I recommend a factory for this
# log in user however you like, alternatively stub `current_user` method
session[:user_id] = user.id
get :index
assert_template :index # render the template since he should have access
Par ailleurs, si vous voulez tester le comportement du contrôleur indépendamment de ce qui est à l'intérieur de la classe de capacité, il est facile de stub la capacité avec un comportement que vous voulez.
def setup
@ability = Object.new
@ability.extend(CanCan::Ability)
@controller.stubs(:current_ability).returns(@ability)
end
test "render index if have read ability on project" do
@ability.can :read, Project
get :index
assert_template :index
end
Si vous disposez des autorisations très complexes, il peut conduire à de nombreuses possibilités de branchement. Si ceux-ci sont tous testés dans la couche de commande il peut conduire à des tests lents et gonflés. Au lieu de cela, je recommande de garder l'autorisation du contrôleur des tests de lumière et tester la fonctionnalité d'autorisation de manière plus approfondie dans le modèle de capacité grâce à des tests unitaires comme indiqué en haut.
Je pense que les besoins d'autorisation à faire principalement pour contrôleurs pour vous assurer que votre autorisation fonctionne correctement avec vos contrôleurs. Donc, pour le rendre DRY vous pouvez mettre en œuvre votre propre matcher
être utilisé comme ceci
let!(:user) {create :user}
before { login_user_request user}
it "grants admin access to show action" do
expect{ get :show, {id: user.id} }.to be_authorized
end
it "denies user access to edit action" do
expect{ get :edit, {id: user.id} }.to be_un_authorized
end
puis mettre en œuvre ces matchers avec votre propre moyen de tester la façon dont une demande sera autorisée ou non
RSpec::Matchers.define :be_authorized do
match do |block|
block.call
expect(response).to be_success
end
def supports_block_expectations?
true
end
end
RSpec::Matchers.define :be_un_authorized do
match do |block|
expect{
block.call
}.to raise_error(Pundit::NotAuthorizedError)
end
def supports_block_expectations?
true
end
end
Pourquoi ne pas inclure un
can :manage, :all do
user.is_ultrasuper == 1
end
dans votre capacité et un param is_ultrasuper dans l'un de vos utilisateurs de fixation:
one:
id: 1
username: my_username
is_ultrasuper: 1
Ensuite, connectez-vous cet utilisateur lors de la configuration dans vos tests. Cela dans les tests, vous devriez être en mesure de faire quoi que ce soit du tout.