RSpec中WorkHistory模型验证测试失败问题咨询
Let's break down the issues with your tests and model validation code step by step:
1. First Test Failure: is_employed: false with empty until_date is passing when it shouldn't
The problem lies in your model validation rule for until_date:
validates :until_date, presence: true, if: -> { :is_employed == false }
Your lambda (-> { :is_employed == false }) is comparing the symbol :is_employed to false—not the instance's actual is_employed attribute value. A symbol will never equal false, so this condition always evaluates to false, meaning the presence validation for until_date never runs. That's why setting until_date = '' (which Rails converts to nil) doesn't mark the record as invalid.
Fix the Validation Rule
Update the lambda to reference the instance's attribute correctly:
validates :until_date, presence: true, if: -> { !is_employed } # Or equivalently: if: -> { is_employed == false }
This checks the real value of the is_employed attribute on the WorkHistory instance, so the validation will trigger when is_employed is false.
2. Second Test Failure: Setting is_employed: 'employed' isn't marking the record as invalid
Rails automatically converts values assigned to boolean attributes. Any non-empty string (like 'employed') gets converted to true, which falls within your inclusion validation's allowed values ([true, false]). That's why the record remains valid even when you set the string value.
Fix the Test
To properly test the inclusion validation, you need to assign a value that isn't converted to true or false, or bypass Rails' type conversion directly. Here are two solid options:
Option 1: Assign nil (if your database allows is_employed to be nil)
it "is invalid when is_employed is nil" do work_history.is_employed = nil expect(work_history.valid?).to eq(false) end
Option 2: Bypass type conversion by setting the attribute directly
Use the attribute hash to set the raw string value without Rails converting it:
it "is invalid when is_employed is a non-boolean string" do work_history[:is_employed] = 'employed' expect(work_history.valid?).to eq(false) end
Final Corrected Code
Updated models/work_history.rb
class WorkHistory < ApplicationRecord belongs_to :account validates :name, :since_date, :position, presence: true validates :is_employed, inclusion: [true, false] validates :until_date, presence: true, if: -> { !is_employed } end
Updated spec/models/work_history_spec.rb
RSpec.describe WorkHistory, type: :model do let(:account) { create(:account) } let(:work_history) { build(:work_history, account: account) } it "is invalid when is_employed is false and until_date is nil" do work_history.is_employed = false work_history.until_date = '' expect(work_history.valid?).to eq(false) end it "is invalid when is_employed is a non-boolean value" do work_history[:is_employed] = 'employed' expect(work_history.valid?).to eq(false) end end
Run your tests again with docker-compose run app rspec spec/models—they should now pass!
内容的提问来源于stack exchange,提问作者Nozomi Iida

