Pergunta

Estou escrevendo retroativamente alguns testes, usando o RSPEC, para um projeto Rails.

Estou usando a jóia de Cancan para fornecer autorização. Eu decidi escrever uma especificação que testará o ability.rb modelo. Depois, testei meus modelos restantes.

Mudei para os controladores e encontrei um enorme problema: estou testando minhas habilidades de novo!

Basicamente, tenho que arrancar uma série de modelos e extrair suas associações; Caso contrário, a resposta apenas retorna 403 Forbidden.
A razão para isso é que o controlador é basicamente responsável por se preocupar com a autorização.

Não sei ao certo para onde ir daqui. Estou saindo de até 6 modelos, apenas para escrever um único teste. EU conhecer as habilidades funcionam, é isso que ability_spec.rb é para.

Portanto, esta pergunta é realmente 2 vezes:

  1. Devo estar testando o modelo de habilidade separadamente?
  2. Os testes do controlador devem se preocupar com as permissões adequadas?

EditarExigir 'spec_helper' incluir o Devise :: testhelpers # para dar seu acesso à sua especificação aos ajudantes

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

Obrigado,
Robbie

Foi útil?

Solução

Eu testo o modelo CANCAN separadamente, mas testando o que ele permitirá em quais condições.

Eu acho que se você estiver fazendo coisas como

authorize! :take_over, @the_world

Então eu acho que você deveria estar testando isso no controlador. Não tenho certeza se você precisa testar todas as 6 versões de seus modelos.

Você pode arrancar a habilidade. Pode? Classe e faça com que responda verdadeiro/falso e teste como o controlador lida quando pode (e mais importante) quando não puder continuar.

Outras dicas

Não tenho certeza se isso é tarde demais para você, mas eu apenas encontrei o mesmo problema e resolvi usando o seguinte amostra de código -

before do
  @user = Factory.create(:user)
    sign_in @user

    @abilities = Ability.new(@user)
    Ability.stub(:new).and_return(@abilities)
  end
end

Eu estalei a habilidade#nova, dando -me uma referência à instância de habilidade que controla o usuário atual. Então, eu posso arrancar habilidades específicas como esta:

@abilities.stub!(:can?).with(:destroy, regatta).and_return(true)

ou dê privilégios de administrador:

@abilities.stub!(:can?).and_return(false)

Semelhante à resposta de Sam, mas na página do Wiki de Cancan nos testes:

Teste do controlador

Se você deseja testar a funcionalidade de autorização no nível um do controlador, é fazer login no usuário que possui as permissões apropriadas.

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

Como alternativa, se você deseja testar o comportamento do controlador independentemente do que está dentro da classe de habilidades, é fácil eliminar a capacidade de qualquer comportamento que você deseja.

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

Se você tiver permissões muito complexas, isso pode levar a muitas possibilidades de ramificação. Se tudo for testado na camada do controlador, poderá levar a testes lentos e inchados. Em vez disso, recomendo manter testes de autorização do controlador e testam a funcionalidade de autorização mais detalhadamente no modelo de habilidade através de testes de unidade, como mostrado na parte superior.

Eu acho que a autorização precisa ser feita principalmente para controladores Para garantir que sua autorização esteja funcionando corretamente com seus controladores. Então, para fazer isso SECO Você pode implementar o seu próprio matcher para ser usado assim

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

e depois implemente esses correspondentes com sua própria maneira de testar como uma solicitação será autorizada ou não

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

Por que você não inclui um

can :manage, :all do
  user.is_ultrasuper == 1
end

em sua capacidade e depois ter um param IS_ULTRASUPER em um dos seus usuários de acessórios:

one: 
  id: 1 
  username: my_username 
  is_ultrasuper: 1

Em seguida, registre este usuário na configuração de seus testes. Isso nos testes, você poderá fazer qualquer coisa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top