简体   繁体   English

RSpec测试自定义验证器

[英]RSpec test custom validator

I have the following validator in my model: 我的模型中有以下验证器:

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

How can I test it using Rspec? 如何使用Rspec进行测试?

Here is what I have tried so far: (thanks to zetetic ) 这是我到目前为止所尝试的:(感谢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

But I get the following errors: 但是我收到以下错误:

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={}>

What am I doing wrong? 我究竟做错了什么? And how can I achieve my goal? 我怎样才能实现目标? Any help or suggestion would be appreciated. 任何帮助或建议将不胜感激。 Thanks. 谢谢。

The problem is that you're expecting @time_event.errors to behave like an array of strings. 问题是你期望@time_event.errors的行为就像一个字符串数组。 It doesn't, it returns ActiveModel::Errors. 它没有,它返回ActiveModel :: Errors。 As others pointed out, you also need to trigger the validations with a call to valid? 正如其他人指出的那样,你还需要通过调用valid?来触发验证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

There are no errors because you haven't called an event that triggers the errors. 没有错误,因为您没有调用触发错误的事件。 This happens normally when a record is created or saved. 这通常在创建或保存记录时发生。 You may not want to hit the database in your test though and then you can use the method valid? 您可能不想在测试中访问数据库,然后您可以使用该方法valid? like this: 像这样:

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

Me personally would put these two tests into one since valid? 我个人会将这两个测试合并为一个有效吗? is called in the first case. 在第一种情况下调用。

Also a minor: if record.end_time is better than if !record.end_time.nil? 也是一个未成年人: if record.end_timeif !record.end_time.nil? . (In my opinion at least.... :-) ) (至少在我看来...... :-))

This solution works for me (using Mongoid): 这个解决方案适合我(使用Mongoid):

The model 该模型

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

The test: 考试:

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

So in your case I'd write a test like this (if using ActiveRecord): 所以在你的情况下,我会写一个这样的测试(如果使用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

I think the record wasnt validated therefore the validatior didn't run and no error was aded. 我认为记录没有经过验证,因此有效性没有运行且没有错误。 You can see this in the code output. 您可以在代码输出中看到这一点。 "validated: false" “验证:false”

try: 尝试:

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

You have not tested the validation actually, plus i would suggest you to make a single spec. 你还没有测试过验证,而且我建议你做一个单一的规范。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM