【问题标题】:Skipping Pundit authorization with Minitest使用 Minitest 跳过 Pundit 授权
【发布时间】:2017-03-12 04:38:14
【问题描述】:

我有 Pundit 的测试设置,使用没有问题:

https://github.com/ksimmons/policy-assertions

就我而言,我的 Pundit / Devise 系统补充了一个注册类型系统来添加角色等。

当我测试我的控制器时,我想完全跳过整个 Devise / Pundit 系统,只关注控制器逻辑,而不是查看我将在策略测试中处理的授权。

我看起来像这样 (http://www.colorfultyping.com/disabling-devise-for-rails-integration-testing/#comment-4718) 但我无法让它工作。

【问题讨论】:

  • 我认为关键是控制器中调用了“授权”这一事实。我什至尝试通过在我的应用程序控制器中注释掉 ':verify_authorized' 来禁用 Pundit。我希望 Pundit 在我测试时始终授权,除非我在测试实际策略。
  • 我的解决方法是只使用具有超级用户权限的用户装置 - 这种方式 Pundit 总是授权。

标签: ruby-on-rails devise minitest pundit


【解决方案1】:

为了在控制器中跳过 Pundit 授权,您需要存根 从 Policy 类的new 方法中返回一个占位符/模拟对象 以true 响应正在测试的操作中的操作策略; 例如for FooController my FooPolicy 返回一个新的自身实例 在index 中调用其操作策略index? 时返回true 控制器动作。

对于 Minitest,它看起来像这样

# - Minitest -
foo_policy = MiniTest::Mock.new
foo_policy.expect :index?, true

FooPolicy.stub :new, foo_policy do
  # your controller action test
end

您将创建一个模拟对象,该对象将扮演 Policy 的新实例的角色 控制器操作中的对象,并返回该模拟对象,如果策略的 new 方法在测试期间在其块范围内被调用。

如果您使用 Mocha,我相信以下方法也可以实现相同的效果 如上所述,但无需在其块中指定测试资产。

# - Mocha -
foo_policy = mock("foo_policy")
foo_policy.expects(:index?).returns(true)

FooPolicy.any_instance.stubs(:new).returns(foo_policy)

另外,您可以使用mock = Object.new 和存根实现类似的模拟对象 通过为mock 内联定义一个方法,如def mock.index?。这 也适用于现有的类,因为 Ruby 允许您重新声明一个方法 对于像 def FooPolicy.new 这样的类内联,并且只在 测试范围。知道了这一点,我们可以拥有def FooPolicy.new 并返回 我们的mock 如下所示

# - Without a Test-framework -
foo_policy = Object.new # create a mock / double
def foo_policy.index?; true; end # stub a method

def FooPolicy.new # stub Policyclass to return double with stubbed method
  foo_policy = Object.new
  def foo_policy.index?; true; end
  foo_policy
end

为了完整起见,我使用 RSpec 并使用以下内容来删除我的 Pundit 我的控制器操作中的策略

# - Rspec -
foo_policy = instance_double("policy", index?: true)
allow(FooPolicy).to receive(:new).and_return(foo_policy)

至于 Devise,我使用以下支持测试助手,并且仅将它们包含在 需要用户在测试前sign_in 的控制器和请求测试:

module DeviseRequestSpecHelpers
  include Warden::Test::Helpers

  def sign_in(resource_or_scope, resource = nil)
    resource ||= resource_or_scope
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    login_as(resource, scope: scope)
  end

  def sign_out(resource_or_scope)
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    logout(scope)
  end
end

Module: Warden::Test::Helpers — Documentation for hassox/warden (master) 有关Warden::Test::Helpers 模块的更多信息

这是因为 Warden 在 Devise 中使用了它的测试助手。 这个Warden::Test::Helpers 模块在包含时会将Warden 切换到它的 test_mode! 及其 login_as 方法会将您的 user 对象设置为 current_user 用于测试,在您的 申请。

参考资料:

【讨论】:

  • 感谢 @sonna 使用多种测试工具提供完整的答案。很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
  • 2014-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多