ruby-on-rails - 在 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。
解决方案
我通过使用 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
推荐阅读
- python - 将异常捕获分开还是在一个try-block中执行它们是否更符合pythonic?Python
- visual-studio - 通过 Visual Studio 代码调试存储库
- java - java.lang.reflect.InaccessibleObjectException:无法使字段私有最终字节 [] java.lang.String.value 可访问:568
- reactjs - 反应状态与实际状态不同步
- ruby-on-rails - Rails 6 ActiveAdmin CSV 导出不维护过滤器
- python - PySimpleGUI 强制文本框旁边的日历框
- load-balancing - 负载均衡器构建:
- python - InvalidArgumentError:键:图像。无法解析序列化的示例。[[{{node ParseSingleExample/ParseSingleExample}}]] [[{{node IteratorGetNext}}]]
- google-chrome - 是否有独立于 Chromium 的 Chrome 的公共问题跟踪器
- python - ValueError:没有为任何变量提供梯度: