RSpec 失败 - 日期比较

RSpec failing - date comparison

所以我有一个 RSpec 测试失败了,我确信这个测试是问题所在,因为从功能的角度来看它工作正常。

总之,end_time应该不是before_start的时候。保存模型后可以正常工作,只有 RSpec 失败,任何指针将不胜感激

chain_plan_spec.rb

# frozen_string_literal: true

# == Schema Information
#
# Table name: chain_plans
#
#  id         :bigint           not null, primary key
#  end_time   :datetime
#  start_time :datetime
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  faction_id :bigint           not null
#
# Indexes
#
#  index_chain_plans_on_faction_id  (faction_id)
#
# Foreign Keys
#
#  fk_rails_...  (faction_id => factions.id)
#
require 'rails_helper'
RSpec.describe ChainPlan, type: :model do
  it { is_expected.to validate_presence_of :start_time }
  it { is_expected.to validate_presence_of :end_time }
  it { is_expected.to validate_presence_of :faction }

  it 'does not have a start date/time before an end date/time' do
    cp = described_class.new
    cp.start_time = Date.now
    cp.end_time = cp.start - 1.minute
    cp.save!

    expect(cp).not_to be_valid
  end
  # TODO: end is 0 minute
  # TODO start is 0 minute
end

chain_plan.rb

# frozen_string_literal: true

# == Schema Information
#
# Table name: chain_plans
#
#  id         :bigint           not null, primary key
#  end_time   :datetime
#  start_time :datetime
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  faction_id :bigint           not null
#
# Indexes
#
#  index_chain_plans_on_faction_id  (faction_id)
#
# Foreign Keys
#
#  fk_rails_...  (faction_id => factions.id)
#
class ChainPlan < ApplicationRecord
  belongs_to :faction
  has_many :chain_plan_slots
  validates :start_time, presence: { on: :create, message: "can't be blank" }
  validates :end_time, presence: { on: :create, message: "can't be blank" }
  validates :faction, presence: { on: :create, message: "can't be blank" }
  validate :end_date_after_start_date?

  private

  def end_date_after_start_date?
    return if end_time.blank? || start_time.blank?

    errors.add(:end_date, 'must be after the start date') if end_time < start_time
  end
end

我认为问题是 Date.now,这不是一个正确的命令 - 至少从 documentation 我找不到 class now 的方法 Date。请改用 Time.now。这对我来说很好。

测试验证时不要使用 expect(object).not_to be_validexpect(object).to be_valid。这只是假阳性和假阴性的配方,因为您实际上并不是在测试单个行为 - 而是在测试设置时同时测试每一个验证。

RSpec.describe ChainPlan, type: :model do
  it 'does not allow an end_time which is after the start_time' do
    cp = described_class.new(
      start_time: Time.current,
      end_time: Time.current - 1.minute
    )
    cp.valid?
    expect(cp.errors.messages_for(:end_time)).to include 'must be after the start date'
  end
  it "allows a valid start_time/end_time combo" do
    cp = described_class.new(
      start_time: Time.current,
      end_time: Time.current.advance(10.minutes)
    )
    cp.valid?
    expect(cp.errors).to_not have_key :end_date
  end
end

而是设置对象,然后对其调用 valid? 以触发验证。在错误对象上写入期望以测试实际行为而不是地毯式轰炸。例如,在这里您会完全错过将错误添加到密钥 :end_date 而不是 :end_time.

的地方

验证本身也可以改进:

class ChainPlan < ApplicationRecord
  belongs_to :faction
  has_many :chain_plan_slots
  validates :start_time, presence: { on: :create, message: "can't be blank" }
  validates :end_time, presence: { on: :create, message: "can't be blank" }
  validates :faction, presence: { on: :create, message: "can't be blank" }
  validate :end_date_after_start_date?, if: ->{ end_time.present? && start_time.present? }

  private

  def end_date_after_start_date?
    errors.add(:end_time, 'must be after the start date') if end_time < start_time
  end
end