为控制器的 before_filter 操作编写规范

Writing spec for before_filter action for a controller

我的控制器是这样的:

before_filter: check_login_status

def check_login_status
  send_response(:not_logged_in) unless user.logged_in?
end

我对此的规范如下:

it 'returns error unless user is not logged in' do
  expect(controller).to receive(:send_response).with(:not_logged_in)
  controller.send(:check_login_status)
end

现在我想写另一个测试:

it 'checks the login status of user before any action' do
  .......
end

我怎样才能完成第二个测试?

您不测试回调 - 您测试行为。

回调是控制器的内部实现细节,并作为私有方法实现(或者至少应该是,如果你做得对的话)。您应该测试应用程序的行为,而不是它如何完成工作。

为了测试身份验证,您需要编写一个请求规范,您可以在其中向端点发送一个真实的 HTTP 请求并编写关于以下内容的期望:

  • 返回的状态码是否正确?
  • 是否重定向了用户?
  • 有没有发生不该发生的副作用?例如正在创建、销毁或更新的记录。
  • 用户是否得到了他们不应该得到的任何信息?

一个例子:

require 'spec_helper'

RSpec.describe "Things", type: :request do
  describe "POST /things" do
    context "when not logged in" do
      let(:action) do
        post '/things', params: { thing: { foo: 'bar' }}
      end

      it "does not allow a thing to be created" do
        expect{ action }.to_not change(Thing, :count)
      end
 
      it "redirects the user to the login page" do
        action
        expect(response).to redirect_to '/login'
      end 

      # etc
    end
  end
end

这种测试可能有些重复和乏味 - 共享示例可以帮助解决这个问题。

或者,您可以正确执行身份验证系统,这样它实际上会引发异常,您可以通过禁用 rescue_from 来测试引发的异常。事实上,您很想往里面一探究竟,这实际上可能是在揭示设计的味道。