在 Rails 中针对 activerecord 对象关系执行测试时出错
Getting errors when execute test in Rails for activerecord object relationship
我有一个部分视图 _patients.html.erb,我想在其中显示咨询模型的嵌套属性,因此我以这种方式访问 ActiveRecord 关系对象:
我的模型
class Patient < ApplicationRecord
belongs_to :medic
has_many :consultations, dependent: :destroy
accepts_nested_attributes_for :consultations
end
class Consultation < ApplicationRecord
belongs_to :patient
end
在我的 dashboard_controller.rb
..some code..
protected
def reason_for_consultation(patient)
patient = patient
@reason = Consultation.where(patient_id: patient.id).order(created_at: :desc).limit(1)
#=> @reason: #<ActiveRecord::Relation [#<Consultation id: 371, reason_for_consultation: "Sunt impedit adipisci molestiae doloremque sed.">]>
@reason_for_consultation = @reason[0].reason_for_consultation
end
helper_method :reason_for_consultation
视图部分_patients.html.erb
<% @patients.each do |patient| %>
.. code ..
<p>Reason for consultation: <%= reason_for_consultation(patient) %></p>
.. code ..
<% end %>
注意:代码工作正常,在视图中显示每个患者的数据,问题是当我 运行 测试(minitest)时,我收到几个这样的警告和错误:
- 弃用警告:#original_exception 已弃用。请改用#cause。 (错误的更多描述后跟):
- Capybara::ElementNotFound:无法找到可见的 link,或
- 预期假为真,或
- 预期响应为 <2XX:成功>,但却是 <500:内部服务器错误>
但是如果我在我的部分中评论:<%# reason_for_consultation(patient) %>
,并且 运行 测试再次全部通过。
所有错误都与仪表板交互有关
知道发生了什么以及如何解决吗?
编辑:
版本:
- rails:5.0.0.1
- 最小测试:5.9.1
- ruby 2.3.3p222
rails 测试轨迹:
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:19)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:19)
FAIL["test_should_be_in_dashboard", DashboardFlowTest, 0.46483432999957586]
test_should_be_in_dashboard#DashboardFlowTest (0.46s)
Expected false to be truthy.
test/integration/dashboard_flow_test.rb:20:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:24)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:24)
ERROR["test_should_be_show_new_patient_form", DashboardFlowTest, 0.5577200539992191]
test_should_be_show_new_patient_form#DashboardFlowTest (0.56s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Create Patient"
test/integration/dashboard_flow_test.rb:25:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:30)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:30)
ERROR["test_should_be_show_patient_list_page", DashboardFlowTest, 0.6530102200049441]
test_should_be_show_patient_list_page#DashboardFlowTest (0.65s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Patient List"
test/integration/dashboard_flow_test.rb:31:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:PaymentMethodsFlowTest> at my_app/test/integration/payment_methods_flow_test.rb:19)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:PaymentMethodsFlowTest> at my_app/test/integration/payment_methods_flow_test.rb:19)
ERROR["test_0001_log into dashboard as premium user", PaymentMethodsFlowTest, 4.802539983000315]
test_0001_log into dashboard as premium user#PaymentMethodsFlowTest (4.80s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Show Payment Methods"
test/integration/payment_methods_flow_test.rb:21:in `block in <class:PaymentMethodsFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:ConsultNewPatientFlowTest> at my_app/test/integration/consult_new_patient_flow_test.rb:37)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:ConsultNewPatientFlowTest> at my_app/test/integration/consult_new_patient_flow_test.rb:37)
ERROR["test_0001_end to end consult a patient", #<Class:0x0055b32a91d1a0>, 4.885057498999231]
test_0001_end to end consult a patient#Medic can consult a new patient Feature Test (4.89s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Create Patient"
test/integration/consult_new_patient_flow_test.rb:39:in `block (2 levels) in <class:ConsultNewPatientFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:PremiumLoginFlowTest> at my_app/test/integration/premium_login_flow_test.rb:20)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:PremiumLoginFlowTest> at my_app/test/integration/premium_login_flow_test.rb:20)
FAIL["test_0001_login premium", #<Class:0x0055b32a8e22f8>, 5.003259566998167]
test_0001_login premium#Medic with account and payment method Feature Test (5.00s)
Expected false to be truthy.
test/integration/premium_login_flow_test.rb:22:in `block (2 levels) in <class:PremiumLoginFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardControllerTest> at my_app/test/controllers/dashboard_controller_test.rb:21)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardControllerTest> at my_app/test/controllers/dashboard_controller_test.rb:21)
FAIL["test_should_get_dashboard", DashboardControllerTest, 5.078975292002724]
test_should_get_dashboard#DashboardControllerTest (5.08s)
Expected response to be a <2XX: success>, but was a <500: Internal Server Error>
test/controllers/dashboard_controller_test.rb:22:in `block in <class:DashboardControllerTest>'
63/63: [==================================================================================================================] 100% Time: 00:00:05, Time: 00:00:05
Finished in 5.30410s
63 tests, 147 assertions, 3 failures, 4 errors, 0 skips
编辑 2:
预期响应为 <2XX:成功>,但为 <500:内部服务器错误>
my_app/test/controllers/dashboard_controller_test.rb:21
require 'test_helper'
class DashboardControllerTest < ActionDispatch::IntegrationTest
# Needed for authenticate user
include Warden::Test::Helpers
setup do
# Login medic for before_filter authenticate_user!
@medic = medics(:medic_one)
@medic.confirmed_at = Time.now
@medic.save
login_as(@medic, :scope => :medic)
# Set payment for medic
@medic.payment_methods.reload
end
test "should get dashboard" do
get dashboard_index_url
assert_response :success
end
end
控制器测试失败表明您的问题所在,页面返回 500 错误状态而不是 2XX 状态 - 这告诉您呈现页面时出错。这也是 Capybara 在页面上找不到任何预期元素的原因(因为页面实际上并未呈现)。如果您查看 test.log
,它应该准确地告诉您错误出现在模板中的哪个位置,但是由于注释掉 <%# reason_for_consultation(patient) %
修复了页面,我们可以非常安全地假设错误所在。
查看 reason_for_consultation
的代码,我们可以看到,如果患者尚未进行咨询,则 @reason[0]
将是 nil
,而 @reason[0].reason_for_consultation
将提高尝试在 nil
上调用 reason_for_consultation
时出错。一种可能的解决方法是使用安全导航运算符并将行更改为
@reason[0]&.reason_for_consultation
注意:将来可能应该重构 routine/partial 的整个实现,以删除您在那里进行的 N + 1 查询。
至于关于 original_exception
的 DEPRECATION WARNING
行 - 如果没有更深入的堆栈跟踪,就不可能说出它实际来自哪里,但请尝试查看 my_app/test/controllers/dashboard_controller_test.rb
第 21 行,看看是什么在那里被调用。可能只是您需要更新一些测试 gem。
我有一个部分视图 _patients.html.erb,我想在其中显示咨询模型的嵌套属性,因此我以这种方式访问 ActiveRecord 关系对象:
我的模型
class Patient < ApplicationRecord
belongs_to :medic
has_many :consultations, dependent: :destroy
accepts_nested_attributes_for :consultations
end
class Consultation < ApplicationRecord
belongs_to :patient
end
在我的 dashboard_controller.rb
..some code..
protected
def reason_for_consultation(patient)
patient = patient
@reason = Consultation.where(patient_id: patient.id).order(created_at: :desc).limit(1)
#=> @reason: #<ActiveRecord::Relation [#<Consultation id: 371, reason_for_consultation: "Sunt impedit adipisci molestiae doloremque sed.">]>
@reason_for_consultation = @reason[0].reason_for_consultation
end
helper_method :reason_for_consultation
视图部分_patients.html.erb
<% @patients.each do |patient| %>
.. code ..
<p>Reason for consultation: <%= reason_for_consultation(patient) %></p>
.. code ..
<% end %>
注意:代码工作正常,在视图中显示每个患者的数据,问题是当我 运行 测试(minitest)时,我收到几个这样的警告和错误:
- 弃用警告:#original_exception 已弃用。请改用#cause。 (错误的更多描述后跟):
- Capybara::ElementNotFound:无法找到可见的 link,或
- 预期假为真,或
- 预期响应为 <2XX:成功>,但却是 <500:内部服务器错误>
但是如果我在我的部分中评论:<%# reason_for_consultation(patient) %>
,并且 运行 测试再次全部通过。
所有错误都与仪表板交互有关
知道发生了什么以及如何解决吗?
编辑:
版本: - rails:5.0.0.1 - 最小测试:5.9.1 - ruby 2.3.3p222
rails 测试轨迹:
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:19)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:19)
FAIL["test_should_be_in_dashboard", DashboardFlowTest, 0.46483432999957586]
test_should_be_in_dashboard#DashboardFlowTest (0.46s)
Expected false to be truthy.
test/integration/dashboard_flow_test.rb:20:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:24)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:24)
ERROR["test_should_be_show_new_patient_form", DashboardFlowTest, 0.5577200539992191]
test_should_be_show_new_patient_form#DashboardFlowTest (0.56s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Create Patient"
test/integration/dashboard_flow_test.rb:25:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:30)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardFlowTest> at my_app/test/integration/dashboard_flow_test.rb:30)
ERROR["test_should_be_show_patient_list_page", DashboardFlowTest, 0.6530102200049441]
test_should_be_show_patient_list_page#DashboardFlowTest (0.65s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Patient List"
test/integration/dashboard_flow_test.rb:31:in `block in <class:DashboardFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:PaymentMethodsFlowTest> at my_app/test/integration/payment_methods_flow_test.rb:19)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:PaymentMethodsFlowTest> at my_app/test/integration/payment_methods_flow_test.rb:19)
ERROR["test_0001_log into dashboard as premium user", PaymentMethodsFlowTest, 4.802539983000315]
test_0001_log into dashboard as premium user#PaymentMethodsFlowTest (4.80s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Show Payment Methods"
test/integration/payment_methods_flow_test.rb:21:in `block in <class:PaymentMethodsFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:ConsultNewPatientFlowTest> at my_app/test/integration/consult_new_patient_flow_test.rb:37)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:ConsultNewPatientFlowTest> at my_app/test/integration/consult_new_patient_flow_test.rb:37)
ERROR["test_0001_end to end consult a patient", #<Class:0x0055b32a91d1a0>, 4.885057498999231]
test_0001_end to end consult a patient#Medic can consult a new patient Feature Test (4.89s)
Capybara::ElementNotFound: Capybara::ElementNotFound: Unable to find visible link "Create Patient"
test/integration/consult_new_patient_flow_test.rb:39:in `block (2 levels) in <class:ConsultNewPatientFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:PremiumLoginFlowTest> at my_app/test/integration/premium_login_flow_test.rb:20)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block (2 levels) in <class:PremiumLoginFlowTest> at my_app/test/integration/premium_login_flow_test.rb:20)
FAIL["test_0001_login premium", #<Class:0x0055b32a8e22f8>, 5.003259566998167]
test_0001_login premium#Medic with account and payment method Feature Test (5.00s)
Expected false to be truthy.
test/integration/premium_login_flow_test.rb:22:in `block (2 levels) in <class:PremiumLoginFlowTest>'
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardControllerTest> at my_app/test/controllers/dashboard_controller_test.rb:21)
DEPRECATION WARNING: #original_exception is deprecated. Use #cause instead. (called from block in <class:DashboardControllerTest> at my_app/test/controllers/dashboard_controller_test.rb:21)
FAIL["test_should_get_dashboard", DashboardControllerTest, 5.078975292002724]
test_should_get_dashboard#DashboardControllerTest (5.08s)
Expected response to be a <2XX: success>, but was a <500: Internal Server Error>
test/controllers/dashboard_controller_test.rb:22:in `block in <class:DashboardControllerTest>'
63/63: [==================================================================================================================] 100% Time: 00:00:05, Time: 00:00:05
Finished in 5.30410s
63 tests, 147 assertions, 3 failures, 4 errors, 0 skips
编辑 2:
预期响应为 <2XX:成功>,但为 <500:内部服务器错误> my_app/test/controllers/dashboard_controller_test.rb:21
require 'test_helper'
class DashboardControllerTest < ActionDispatch::IntegrationTest
# Needed for authenticate user
include Warden::Test::Helpers
setup do
# Login medic for before_filter authenticate_user!
@medic = medics(:medic_one)
@medic.confirmed_at = Time.now
@medic.save
login_as(@medic, :scope => :medic)
# Set payment for medic
@medic.payment_methods.reload
end
test "should get dashboard" do
get dashboard_index_url
assert_response :success
end
end
控制器测试失败表明您的问题所在,页面返回 500 错误状态而不是 2XX 状态 - 这告诉您呈现页面时出错。这也是 Capybara 在页面上找不到任何预期元素的原因(因为页面实际上并未呈现)。如果您查看 test.log
,它应该准确地告诉您错误出现在模板中的哪个位置,但是由于注释掉 <%# reason_for_consultation(patient) %
修复了页面,我们可以非常安全地假设错误所在。
查看 reason_for_consultation
的代码,我们可以看到,如果患者尚未进行咨询,则 @reason[0]
将是 nil
,而 @reason[0].reason_for_consultation
将提高尝试在 nil
上调用 reason_for_consultation
时出错。一种可能的解决方法是使用安全导航运算符并将行更改为
@reason[0]&.reason_for_consultation
注意:将来可能应该重构 routine/partial 的整个实现,以删除您在那里进行的 N + 1 查询。
至于关于 original_exception
的 DEPRECATION WARNING
行 - 如果没有更深入的堆栈跟踪,就不可能说出它实际来自哪里,但请尝试查看 my_app/test/controllers/dashboard_controller_test.rb
第 21 行,看看是什么在那里被调用。可能只是您需要更新一些测试 gem。