如何编写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
相关产品推荐
相关产品推荐

