首页 > 解决方案 > 在 Rspec 请求测试中使用 Session、Cookie 或 Current_something

问题描述

我正在尝试在我正在进行的这个新项目中遵循新的 Rails 测试约定。因此我设置了单元测试、请求测试和功能测试。问题是在请求测试中,不支持 Capybara 和会话信息。

除了由 Devise 设置 current_user 方法外,我的应用程序还有另一个类似的方法,称为 current_client。对于我的一些控制器,我需要检查 current_user 是否已登录。这适用于 Devise authenticate_user!在 before_action 中调用。但是对于一些控制器,我还需要检查是否首先选择了一个客户端(例如,如果你想添加事务,它们需要与当前正在处理的客户端绑定)。

所以我添加了另一个 before_action 方法来检查是否还选择了客户端。这在 Capybara 的功能测试中效果很好,我可以在其中模拟用户登录和用户选择要处理的客户端。但是在请求测试中,它不起作用。

我首先测试尝试在没有用户登录的情况下访问端点并且响应不成功(因为它应该)并且它重定向到登录页面。但是然后我需要在用户登录并选择客户端的情况下运行我的测试。设计助手提供了一个 sign_in(user) 方法。但是我无法让我的 current_user 方法工作,而且我似乎无法正确设置它。因此,这些测试失败并重定向到另一个页面,要求用户选择客户端。

我已经尝试了很多我看到的建议。就像尝试存根 current_client 方法一样,尝试向 GET 调用提供会话信息。我什至尝试检查 Devise 源代码以了解他们如何在 Rspec 中模拟 current_user 方法,但无法真正找到魔法发生的地方。

这是代码

current_client 方法看起来像这样

def current_client
  current_client ||= Client.find(session[:client_id]) if session[:client_id]
  rescue ActiveRecord::RecordNotFound
  current_client = nil
end

这就是用户选择要处理的客户端后的设置方式

def set_current_client(client)
  session[:client_id] = client.id
end

这是我的测试文件中的代码,我首先创建了 2 个用户,以便我可以测试用户 1 不能访问用户 2 的事务。(我正在使用 FactoryBot)然后我创建 2 个客户端(每个用户一个)

RSpec.describe "Rooms", :type => :request do 
  let!(:user) {create(:user)}
  let!(:user2) {create(:user2)}

  let!(:client) {create(:client, user: user)}
  let!(:client) {create(:client, user: user2)}

以下作品

describe 'User Not Signed In' do 
  describe 'GET #index' do
    subject { get transact_path} 
    it "returns an unsuccessful response" do 
      subject
      expect(response).to_not be_successful
  end

  it "redirects to sign in page" do 
    subject
    expect(response).to redirect_to (new_user_session_path)
  end
end

以下没有。sign_in(user) 方法在 before 块中起作用,并且不会重定向到登录页面。但是,响应不成功,因为 current_client 未设置,并且我尝试在 before 块中以多种方式设置它但没有成功。

describe 'User Signed In' do 
  before do 
    sign_in(user)
  end

describe 'GET #index' do 
  it "returns a successful response" do 
    get transact_path
      expect(response).to be_successful
    end
  end
end

我知道最佳实践远离了控制器测试,因为理论上呈现的视图或分配的实例变量与控制器没有任何关系。但就我而言,我只是想测试我的端点,现在我不能,因为我无法设置我的 current_client。

标签: ruby-on-railsrubyrspec

解决方案


我通过使用 DHH 自己建议的解决方案找到了解决方法。

无需尝试对 current_client 变量进行存根或尝试在 ActionDispatch::Cookies 的内部设置某些东西,您只需对负责设置我的 current_client 变量的任何控制器进行 POST 或 GET 调用。

所以对我来说,解决方案是将以下代码放在 before do 块中

before do
  sign_in(user)
  get select_client_path, params: {id: client.id}
end

推荐阅读