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

RSpec中WorkHistory模型验证测试失败问题咨询

Why Your RSpec Tests for WorkHistory Are Failing (and How to Fix Them)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:02:28