カンカン経由で認可されたコントローラーのテスト中は乾燥したまま

StackOverflow https://stackoverflow.com/questions/4047085

  •  27-09-2019
  •  | 
  •  

質問

Railsプロジェクトのために、RSPECを使用して、いくつかのテストを遡及的に書いています。

Cancan Gemを使用して許可を提供しています。テストする仕様を書くことにしました ability.rb モデル。その後、残りのモデルをテストしました。

私はコントローラーに移りました、そして、私は巨大なひっかきりに遭遇しました:私は自分の能力をもう一度テストしています!

基本的に、私は一連のモデルを突き刺し、彼らの関連付けを突き刺す必要があります。それ以外の場合は、応答が返されます 403 Forbidden.
この理由は、コントローラーが基本的に許可を心配することを担当しているためです。

ここからどこへ行くのかよくわかりません。単一のテストを作成するために、最大6つのモデルを突き刺しています。私 知る 能力は機能します、それが何ですか ability_spec.rb のためです。

したがって、この質問は本当に2倍です:

  1. 能力モデルを個別にテストする必要がありますか?
  2. コントローラーテストは、適切な許可に関係する必要がありますか?

編集'spec_helper'を要求するdevise :: testhelpers#を含めるために、ヘルパーへの仕様アクセスを提供します

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

ありがとう、
ロビー

役に立ちましたか?

解決

CANCANモデルを個別にテストしますが、どのような条件で何が許可されるかをテストします。

あなたがようなことをしているなら、私は思う

authorize! :take_over, @the_world

それから、私はあなたがコントローラーでそれをテストするべきだと思います。ただし、モデルの6つのバージョンすべてをテストする必要があるかどうかはわかりません。

あなたは能力を突き刺すことができます。クラスとそれを真の/falseに応答させ、コントローラーが続行できない場合(およびさらに重要なことに)どのように処理するかをテストします。

他のヒント

これがあなたにとって遅すぎるかどうかはわかりませんが、私は同じ問題に遭遇し、次のコードサンプルを使用して解決しました -

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

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

私は能力#newを突き刺し、現在のユーザーを制御する能力のインスタンスへの参照を与えてくれました。それから、私はこのような特定の能力を突き刺すことができます:

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

または管理者の特権を与える:

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

サムの答えに似ていますが、テストに関するCancan Wikiページから:

コントローラーテスト

コントローラーレベルのオプションで認証機能をテストする場合は、適切な権限を持つユーザーをログインすることです。

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

または、能力クラス内にあるものとは独立してコントローラーの動作をテストしたい場合は、必要な動作で能力を簡単に締め出すことができます。

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

あなたが非常に複雑な許可を持っている場合、それは多くの分岐の可能性につながる可能性があります。これらがすべてコントローラー層でテストされている場合、遅いテストと肥大化したテストにつながる可能性があります。代わりに、コントローラー認証テストを軽視し、上部に示すように単体テストを通じて能力モデルで認証機能をより徹底的にテストすることをお勧めします。

主に許可を行う必要があると思います コントローラー 許可がコントローラーで正しく機能していることを確認してください。それを作るために ドライ あなたはあなた自身を実装できます matcher このように使用されます

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

そして、これらのマッチャーを独自の方法で実装して、リクエストがどのように承認されるかをテストするかどうかをテストします

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

含めてみませんか

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

あなたの能力において、あなたのフィクスチャユーザーの1人にis_ultrasuper paramを持っています:

one: 
  id: 1 
  username: my_username 
  is_ultrasuper: 1

次に、テストのセットアップでこのユーザーをログに記録します。これは、テストでは何でもできるはずです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top