如何使用默认测试框架(minitest)测试控制器测试中的cancancan功能

时间:2015-12-27 21:20:48

标签: ruby-on-rails unit-testing minitest cancancan

在我的rails应用程序中,我有两个用户角色:'student'和'admin'。他们对不同的页面具有不同的访问权限,例如,“admin”可以访问列表用户页面(索引),但“学生”不能访问。这是使用cancancan控制的。

现在我正在为控制器编写测试,因为我有两个不同的角色(据我所知),我需要针对单个行为进行两次单独的测试,例如:

test "should get index for admin" do
    sign_in(users(:admin))
    get "index"
    assert_response :success
end

test "should not get index for student" do
    sign_in(users(:student))
    get "index"
    assert_response :unauthorized
end

其中sign_in(*)是处理用户登录(会话等)的方法

当我考虑添加更多角色(例如'manager','agent')时,我需要在每次添加角色时为所有控制器方法添加新测试。这很乏味而不是“干”,所以我试图找到一种更优雅的方式来处理这个问题。这是我的第一个想法:

在我的test_helper.rb中,我添加了:

def assert_admin_only(&block)
    sign_in(users(:admin))
    instance_exec(&block)
    assert_response :success
    sign_out

    sign_in(users(:student))
    instance_exec(&block)
    assert_response :unauthorized
    sign_out

    sign_in(users(:agent))
    instance_exec(&block)
    assert_response :unauthorized
    sign_out
end

然后在我的测试中:

test "should get index for admin only" do
    assert_admin_only do
        get "index"
    end
end

因此,每次添加新角色时,我只需在test_helper.rb方法中添加几行以测试功能。

然而,它并没有像我想的那样工作,因为“功能测试允许你测试每个测试方法的单个控制器动作。”根据{{​​3}},在我的代码中,我发动了两个动作甚至更多动作。出于某种原因,我无法弄清楚,似乎sign_insign_out实际上并没有改变current_user(尽管它们在实际请求中完美地工作),这实际上使我的尝试失败了。

总之,我希望将我的测试重用于不同的用户角色,这样我每次添加新角色时都不必浪费时间复制和粘贴现有代码。如果你们能提供一些很棒的想法,我将非常感激。

1 个答案:

答案 0 :(得分:0)

例如:

require 'test_helper'

class ArticlesControllerTest < ActionController::TestCase
  include Devise::TestHelpers

  setup do
    @article = articles(:one)
    @admin = users(:admin)
    @expert = users(:expert)
    @user = users(:emelya)
    @student = users(:student)
  end

  test "should get index if admin" do
    sign_in @admin
    ability = Ability.new(@admin)
    assert ability.can? :index, Article

    get :index
    assert_response :success
    assert_not_nil assigns(:articles)
  end


  test "should not get index for other users" do
    [@expert, @user, @student] do |user|
      sign_in user
      ability = Ability.new(user)
      assert ability.cannot? :index, Article

      assert_raise CanCan::AccessDenied do
        get :index
      end

      sign_out user
    end
  end

end