自定义验证器测试 - 包含错误?

Custom Validator Test - Contains Errors?

在我的 rails 项目中编写了一个自定义验证器,并想编写一个测试 nil 何时被传递到记录中。

验证者代码

class FutureValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value == nil
      record.errors[attribute] << "can't be nil"
    elsif value <= Time.now
      record.errors[attribute] << (options[:message] || "can't be in the past!")
    end
  end
end

可能的测试

test "future validator rejects nil values" do
  @obj.future = nil
  assert_includes @obj.errors
end

我不仅想编写一个测试来检查 assert_not @obj.valid?,而且还想实际证明错误消息正在被传回。如果这要求太多,我会满足于知道错误消息返回但目前我的测试不工作。

正在返回

ArgumentError: wrong number of arguments (1 for 2..3)

更新 接近绿色测试

  test "future validator rejects nil values" do
    @obj.future = nil
    @obj.valid?
    assert_includes @obj.errors.messages, {future: ["can't be nil"]}
  end

回来了

FutureValidatorTest#test_future_validator_rejects_nil_values [/Users/rwdonnard/WorkSpace/charter-pay-api/test/models/future_validator_test.rb:42]: Expected {:future=>["can't be nil"]} to include {:future=>["can't be nil"]}.

问题似乎是您测试 class 的方式,并且很可能是 assert_includes 引发的异常。 assert_includes 需要至少 2 个参数,第一个是集合,第二个是您希望包含的对象,在您的情况下分别是错误数组和您期望的错误。如果你不填充 @obj.errors 集合,你的测试也会失败,这需要调用 @obj.valid?

您的测试应如下所示:

test "future validator rejects nil values" do
  @obj.future = nil
  @obj.valid?
  assert_includes @obj.errors.messages, { future: ["can't be nil"] }
end

如果 future.nil? 无论是否进行了其他验证,您都可以通过这种方式确保您的模型无效。


我还建议您不要在您的自定义验证器中检查是否存在,因为 Rails 已经为此提供了一种方法。你可以让你的验证器看起来像这样:

class FutureValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value <= Time.now
      record.errors[attribute] << (options[:message] || "can't be in the past!")
    end
  end
end

并像这样在您的模型中设置验证:

class SomeClass < ActiveRecord::Base
  validates :future, presence: true, future: true
end

您还可以简化测试,例如:

test "is invalid with nil future date" do
  @obj.future = nil
  @obj.valid?
  assert_includes @obj.errors.messages[:future], "can't be nil"
end

test "future validator rejects past dates" do
  @obj.future = Date.new(1987, 1, 1)
  @obj.valid?
  assert_includes @obj.errors.messages[:future], "can't be in the past!"
end