【问题标题】:RSpec test custom validatorRSpec 测试自定义验证器
【发布时间】:2013-02-28 13:14:53
【问题描述】:

我的模型中有以下验证器:

class ContinuumValidator < ActiveModel::Validator
  def validate(record)
    if !record.end_time.nil? and record.end_time < record.start_time
      record.errors[:base] << "An event can not be finished if it did not start yet..."
    end
  end
end

class Hrm::TimeEvent < ActiveRecord::Base
  validates_with ContinuumValidator
end

如何使用 Rspec 对其进行测试?

这是我迄今为止尝试过的:(感谢zetetic

describe "validation error" do
  before do
    @time_event = Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2)
  end

  it "should not be valid if end time is lower than start time" do
    @time_event.should_not be_valid
  end

  it "raises an error if end time is lower than start time" do
    @time_event.errors.should include("An event can not be finished if it did not start yet...")
  end
end

但我收到以下错误:

1) Hrm::TimeEvent validation error raises an error if end time is lower than start time
   Failure/Error: @time_event.errors.should include("An event can not be finished if it did not start yet...")

   expected #<ActiveModel::Errors:0x007fd1d8e02c50 @base=#<Hrm::TimeEvent id: nil, start_time: "2012-10-05 08:00:00", end_time: "2012-10-05 07:00:00", event_type: 2, employee_id: nil, created_at: nil, updated_at: nil, not_punched: false, validated: false, replace_id: nil>, @messages={}> to include "An event can not be finished if it did not start yet..."

   Diff:
   @@ -1,2 +1,5 @@
   -["An event can not be finished if it did not start yet..."]
   +#<ActiveModel::Errors:0x007fd1d8e02c50
   + @base=
   +  #<Hrm::TimeEvent id: nil, start_time: "2012-10-05 08:00:00", end_time: "2012-10-05 07:00:00", event_type: 2, employee_id: nil, created_at: nil, updated_at: nil, not_punched: false, validated: false, replace_id: nil>,
   + @messages={}>

我做错了什么?我怎样才能实现我的目标? 任何帮助或建议将不胜感激。 谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby rspec validation rspec-rails


    【解决方案1】:

    问题是你期望@time_event.errors 表现得像一个字符串数组。它没有,它返回 ActiveModel::Errors。正如其他人指出的那样,您还需要通过调用 valid? 来触发验证:

    it "raises an error if end time is lower than start time" do
      @time_event.valid?
      @time_event.errors.full_messages.should include("An event can not be finished if it did not start yet...")
    end
    

    【讨论】:

    • 你说得对,我需要添加 full_messages 才能得到错误。但是就像其他人说的那样,我需要使用valid? 实际测试验证
    【解决方案2】:

    此解决方案适用于我(使用 Mongoid):

    模型

    class OpLog
    ...
    field :from_status, type: String
    field :to_status,   type: String
    ...
    validate :states_must_differ
    
    def states_must_differ
      if self.from_status == self.to_status
        errors.add(:from_status, "must differ from 'to_status'")
        errors.add(:to_status, "must differ from 'from_status'")
      end
    end
    ...
    end
    

    测试:

    it 'is expected to have different states' do
      expect { create(:oplog, from_status: 'created', to_status: 'created').to raise_error(Mongoid::Errors::Validations) }
    end
    

    所以在你的情况下,我会写一个这样的测试(如果使用 ActiveRecord):

    it 'raises an error if end time is lower than start time' do
      expect { create(Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2)) }.to raise_error(ActiveRecord::Errors)
    end
    

    【讨论】:

      【解决方案3】:

      没有错误是因为您没有调用触发错误的事件。这通常在创建或保存记录时发生。不过,您可能不想在测试中访问数据库,然后您可以像这样使用valid? 方法:

      it "raises an error if end time is lower than start time" do
        @time_event.valid?
        @time_event.errors.should include("An event can not be finished if it did not start yet...")
      end
      

      我个人会将这两个测试合二为一,因为有效?在第一种情况下调用。

      还有一点:if record.end_timeif !record.end_time.nil? 好。 (至少在我看来.... :-))

      【讨论】:

      • 你是对的,但就像@Benjamin Sullivan 建议的那样,我还需要将 full_messages 添加到错误中,以便我的测试通过。也感谢未成年人:)
      【解决方案4】:

      我认为记录没有被验证,因此验证器没有运行并且没有添加错误。您可以在代码输出中看到这一点。 “验证:假”

      尝试:

      it "raises an error if end time is lower than start time" do
        @time_event.valid?
        @time_event.errors.should include("An event can not be finished if it did not start yet...")
      end
      

      【讨论】:

        【解决方案5】:

        您实际上还没有测试验证,另外我建议您制定一个规范。

        describe "validation error" do
          before { @time_event = Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2) }
        
          it "raises an error if end time is lower than start time" do
            @time_event.valid?
            @time_event.errors.should include("An event can not be finished if it did not start yet...")
          end
        end
        
        class ContinuumValidator < ActiveModel::Validator
          def validate(record)
            if record.end_time and record.end_time < record.start_time
              record.error.add_to_base << "An event can not be finished if it did not start yet..."
            end
          end
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-06
          • 1970-01-01
          相关资源
          最近更新 更多