ruby-on-rails 模型和before_create方法的Rspecs

iibxawm4  于 2023-01-22  发布在  Ruby
关注(0)|答案(2)|浏览(150)

我有型号名称:UserApplicationPatient。该模型具有两个关联:

belongs_to :patient
  belongs_to :customer

  before_create :set_defaults

  private

  def set_defaults
    self.enrol_date_and_time = Time.now.utc
    self.pap = '1'
    self.flg = '1'
    self.patient_num = "hos_#{patient_id}"
  end

用户应用程序工厂患者

FactoryBot.define do
  factory :user_application_patient do
    association :patient
    association :customer
    before(:create) do |user_application_patient, evaluator|
      FactoryBot.create(:patient)
      FactoryBot.create(:customer)
    end
  end
end

型号规格:

require 'spec_helper'

 describe UserApplicationPatient do
   describe "required attributes" do
   let!(:user_application_patient) { described_class.create }

   it "return an error with all required attributes" do
    expect(user_application_patient.errors.messages).to eq(
     { patient:         ["must exist"],
       customer:        ["must exist"]
     },
    )
  end

 end
end

这是我第一次写模型的规格说明,谁能告诉我如何写set_defaults before_create方法和工厂的规格说明,我写的是对是错。

bpzcxfmw

bpzcxfmw1#

由于您是在before_create钩子中设置默认值,因此我建议这样验证它

describe UserApplicationPatient do
   describe "required attributes" do
   
   let!(:user_application_patient) { described_class.create }

    it "return an error with all required attributes" do
      # it will validate if your default values are populating when you are creating a new object
      expect(user_application_patient.pap).to eq('1')
    end

  end
end
ubof19bj

ubof19bj2#

要测试是否设置了默认值,请创建一个用户并测试是否设置了默认值。

  • 您肯定不想使用let!,除非需要,否则不需要创建对象。
  • 因为我们正在测试create,所以这里根本没有使用let
  • 我们如何测试Time.now?我们可以冻结时间!
  • 我假设patient_id应该是patient.id

这是第一关。

it 'will set default attributes on create' do
  freeze_time do
    # Time will be the same everywhere in this block.

    uap = create(:user_application_patient)

    expect(uap).to have_attributes(
      enrol_date_and_time: Time.now.utc,
      pap: '1',
      flg: '1',
      patient_num: "hos_#{uap.patient.id}"
    )
  end
end

it 'will not override existing attributes' do
  uap_attributes = {
    enrol_date_and_time: 2.days.ago,
    pap: '23',
    flg: '42',
    patient_num: "hos_1234"
  }
  uap = create(:user_application_patient, **uap_attributes)

  expect(uap).to have_attributes(**uap_attributes)
end

这些可能会失败。

  • 默认值在验证 * 后 * 设置。
  • 现有属性将被覆盖。
  • 什么是patient_id

我们可以将设置默认值改为before validation,这样对象就可以通过验证,而且我们还可以在将对象写入数据库之前查看对象的属性。
我们可以修改set_defaults,使其不会覆盖现有属性。
不应该使用Time.now,它不知道时区。Use Time.current。并且没有理由传入UTC,数据库将存储UTC的时间,Rails将为您转换。

belongs_to :patient
  belongs_to :customer

  before_validation :set_defaults

  private

  def set_defaults
    self.enrol_date_and_time ||= Time.current
    self.pap ||= '1'
    self.flg ||= '1'
    self.patient_num ||= "hos_#{patient.id}"
  end

我们还可以让您的工厂更灵活一些。

FactoryBot.define do
  factory :user_application_patient do
    association :patient, strategy: :create
    association :customer, strategy: :create
  end
end

这样,无论您是build(:user_application_patient)还是create(:user_application_patient),都会创建患者和客户。这对于user_application_patient能够引用其patient.id是必要的。
一般来说,不要在创建时做任何事情。

相关问题