You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写UserApplicationPatient的before_create测试及验证工厂正确性

UserApplicationPatient 模型测试与 FactoryBot 工厂验证指南

一、FactoryBot 工厂正确性验证

先给出符合规范的工厂示例,再说明核心检查要点:

# spec/factories/user_application_patients.rb
FactoryBot.define do
  factory :user_application_patient do
    # 关联需确保对应工厂存在,用association避免不必要的数据库写入
    patient { association :patient }
    customer { association :customer }

    # 回调负责设置的字段(enrol_date_and_time、pap、flg、patient_num)不要硬编码默认值
    # 如需测试手动覆盖场景,用trait扩展:
    trait :with_custom_enrol_date do
      enrol_date_and_time { 1.day.ago }
    end
  end
end

工厂检查关键点

  • 关联对象用association方法,默认会以build方式初始化关联对象,避免每次创建工厂都生成数据库记录,提升测试速度;若需强制创建关联记录,可加strategy: :create
  • 回调管控的字段不要在工厂里默认赋值,否则会覆盖回调逻辑,失去测试意义
  • 用trait封装特殊场景(比如手动设置字段值),方便在不同测试用例中复用

二、set_defaults 回调的测试方法

假设你的set_defaults方法实现如下(常见逻辑):

# app/models/user_application_patient.rb
class UserApplicationPatient < ApplicationRecord
  belongs_to :patient
  belongs_to :customer

  before_create :set_defaults

  private

  def set_defaults
    self.enrol_date_and_time ||= Time.current
    self.pap ||= 'default_pap'
    self.flg ||= true
    self.patient_num ||= generate_unique_patient_num # 假设是生成唯一编号的方法
  end
end

对应的RSpec测试可以这么写:

# spec/models/user_application_patient_spec.rb
require 'rails_helper'

RSpec.describe UserApplicationPatient, type: :model do
  describe "before_create callback: set_defaults" do
    let(:patient) { create(:patient) }
    let(:customer) { create(:customer) }

    context "when no values are provided for callback-managed fields" do
      it "sets correct default values" do
        user_app_patient = build(:user_application_patient, patient: patient, customer: customer)
        
        # 验证保存前字段未赋值
        expect(user_app_patient.enrol_date_and_time).to be_nil
        expect(user_app_patient.pap).to be_nil
        expect(user_app_patient.flg).to be_nil
        expect(user_app_patient.patient_num).to be_nil

        user_app_patient.save

        # 验证保存后默认值已设置
        expect(user_app_patient.enrol_date_and_time).to be_within(1.second).of(Time.current)
        expect(user_app_patient.pap).to eq('default_pap')
        expect(user_app_patient.flg).to be(true)
        expect(user_app_patient.patient_num).not_to be_nil
      end
    end

    context "when values are manually provided" do
      it "preserves manually set values instead of using defaults" do
        custom_enrol_date = 3.days.ago
        custom_pap = 'custom_pap_value'
        custom_flg = false
        custom_patient_num = 'PAT-001'

        user_app_patient = build(
          :user_application_patient,
          patient: patient,
          customer: customer,
          enrol_date_and_time: custom_enrol_date,
          pap: custom_pap,
          flg: custom_flg,
          patient_num: custom_patient_num
        )

        user_app_patient.save

        # 验证手动值未被回调覆盖
        expect(user_app_patient.enrol_date_and_time).to eq(custom_enrol_date)
        expect(user_app_patient.pap).to eq(custom_pap)
        expect(user_app_patient.flg).to be(custom_flg)
        expect(user_app_patient.patient_num).to eq(custom_patient_num)
      end
    end
  end
end

测试注意事项

  • 用build初始化对象,能清晰验证“保存前字段为空、保存后被赋值”的完整流程
  • 时间字段用be_within(1.second).of(Time.current),避免因测试执行时差导致断言失败
  • 若patient_num有特定格式要求,可单独加断言验证格式(比如expect(user_app_patient.patient_num).to match(/PAT-\d{3}/))
  • 必须覆盖“依赖默认值”和“手动覆盖默认值”两种场景,确保回调逻辑的健壮性

内容的提问来源于stack exchange,提问作者Kumar Nikhil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:01:30