在 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)时,我收到几个这样的警告和错误:

但是如果我在我的部分中评论:<%# 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_exceptionDEPRECATION WARNING 行 - 如果没有更深入的堆栈跟踪,就不可能说出它实际来自哪里,但请尝试查看 my_app/test/controllers/dashboard_controller_test.rb 第 21 行,看看是什么在那里被调用。可能只是您需要更新一些测试 gem。