Rails:使用 RSpec 测试授权 (Pundit)

Rails: Testing authorization (Pundit) with RSpec

我想用 RSpec 彻底测试 Rails 应用程序授权设置 (Pundit)。

  1. Pundit docs and other respectful sources 建议为 Pundit 策略 classes 编写单元测试。这些测试是测试行为(好)还是实现细节(坏)?

  2. 如果我们实际上是在测试行为,那么如果我们最终从 Pundit 切换到另一个授权 gem 或推出我们自己的授权,我们的测试不应该仍然通过吗?

  3. 假设不小心从控制器操作中删除了对 authorize 方法的调用,使其保持打开状态以供 public 访问。 Pundit 政策测试将继续通过。如果我们没有其他测试涵盖这一点,我们的测试套件可能全是绿色,而我们的应用程序存在严重的安全漏洞。我们怎样才能避免这种情况?也许为 Pundit 控制器 classes 编写单元测试,为控制器单独进行单元测试并在控制器测试中模拟 authorize 方法以确保它们被调用?

编辑: 转念一想,对于 [=43] 的实现细节和 public API 之间的区别,我判断失误了=].调用特定 public 方法、传递特定参数并期望特定 return 值是对任何 class 进行单元测试(和使用)的要求。请忽略第 3 项,因为 我原来的论点是无效的。

  1. 我们可以编写控制器或请求规范,而不是测试 Pundit 策略 classes,以不同的用户角色登录,调用控制器操作并断言访问是被授予还是被拒绝。在这种方法中,即使我们切换到另一个授权 gem,测试也会继续通过。此外,如果不调用 authorize 方法,它们将失败。但是,这些将是集成测试,并且应该比单元测试 Pundit 策略 classes 慢。这会是测试授权设置的更好方法吗?

提前致谢。

1) The Pundit docs and other respectful sources) suggest writing unit tests for Pundit policy classes. Are those tests testing behavior (good) or implementation details (bad)?

好的策略规范正在测试系统组件的行为。并非每个不测试整个系统的规范都是邪恶的。它更像是测试 是做什么的 - 而不是 它是如何做的 .

您可以将此比作测试服务对象或任何其他组件。

我发现策略规范是一种非常简洁和准确的测试授权行为的方法,无需额外的抽象层(HTTP、应用程序状态...)。这很像模型规范如何更好地测试验证边缘案例而不是拖着 Capybara。

2) If we were actually testing behavior, shouldn't our tests still pass if we eventually switched from Pundit to another authorization gem or rolled our own authorization?

是的 - 但对于系统中的任何组件来说,这几乎都是有争议的。 您的更高级别规格(请求和功能)应该仍然通过(这也包括控制器正确集成 Pundit)。

3) Suppose a call to the authorize method is accidentally removed from a controller action, leaving it open for public access. Pundit policy tests will keep passing. If we have no other tests covering this, our test suite may be all green while our app has a serious security vulnerability. How can we avoid this? Maybe write unit tests for Pundit controller classes, separate unit tests for controllers and mock the authorize method in the controller tests to ensure they are called?

Controller tests are depreachiated in Rails 5。使用请求或功能规范而不是窥探内部结构。

您应该有请求/功能规范,以确保用户无法执行他们无权执行的操作。例如,在 API 的请求规范中,您将检查响应代码是否为 Unauthorised (401)。如果您偏执,还可以检查是否未执行任何更改。

对于功能规范,您测试用户是否被重定向或通知他们无法执行该操作。

再次测试是做什么的 - 而不是它是如何做的

因为这是重复的,你可以用 shared examples 把它弄干。

4) Instead of testing Pundit policy classes, we could write controller or request specs that login with different user roles, call the controller actions and assert whether access was granted or denied. In this approach, the tests would keep passing even if we switched to another authorization gem. Also, they would fail if the authorize method is not called. However, these would be integration tests and should be slower that unit testing Pundit policy classes. Could that be a better way to test the authorization setup?

同样这里的选择不是二元的。两种类型的测试都提供了价值。您可以通过单独的集成测试来获得,但要涵盖所有可能的情况和边缘情况既困难又缓慢。