如何编写rspec测试来指定无效日期对Rails模型无效?

时间:2013-03-17 06:59:42

标签: ruby-on-rails-3 rspec

查看

<%= form_for(@new_credit_entry) do |f| %>
    <%= f.date_select :created_on%>

我看到我被允许指定无效日期。这会产生一个params哈希,如下所示

"credit"=>{"created_on(1i)"=>"2013",
 "created_on(2i)"=>"2",
 "created_on(3i)"=>"31"

这当然是一个不正确的日期。所以我知道我的模型需要对此进行验证 - 可能会使用validates_timeliness gem。我需要知道的是如何在规范中模拟这个

这是一些rails控制台输出

irb(main):056:0> x = Credit.new(created_on: "2013-02-30")
=> #<Credit id: nil, description: nil, credit_category_id: nil, amount: nil, created_on: nil, created_at: nil, updated_at: nil>
irb(main):058:0> x.created_on_before_type_cast
=> "2013-02-30"
irb(main):060:0> x.created_on
=> nil

irb(main):057:0> y = Credit.new(created_on: "2013-03-03")
=> #<Credit id: nil, description: nil, credit_category_id: nil, amount: nil, created_on: "2013-03-03", created_at: nil, updated_at: nil>
irb(main):059:0> y.created_on_before_type_cast
=> "2013-03-03"
irb(main):061:0> y.created_on
=> Sun, 03 Mar 2013

irb(main):062:0> z = Credit.new("created_on(1i)"=>"2013",
irb(main):063:1*  "created_on(2i)"=>"2",
irb(main):064:1*  "created_on(3i)"=>"31")
=> #<Credit id: nil, description: nil, credit_category_id: nil, amount: nil, created_on: "2013-03-03", created_at: nil, updated_at: nil>
irb(main):065:0> z.created_on
=> Sun, 03 Mar 2013
irb(main):066:0> z.created_on_before_type_cast
=> Sun, 03 Mar 2013

1 个答案:

答案 0 :(得分:1)

如果您使用validates_timeliness,则会拒绝您在上面尝试的无效日期。该模型无效,created_on将为nil。这包括你提到的日期换行问题。

安装validates_timeliness后,模型中只需要:

validates_date :created_on

这是一个测试各种场景的规范:

describe Credit do
  it "rejects single digits" do
    credit = Credit.new created_on: "3"
    credit.should_not be_valid
    credit.created_on.should be_nil
  end

  it "rejects bad dates" do
    credit = Credit.new created_on: "2013-02-31"
    credit.should_not be_valid
    credit.created_on.should be_nil
  end

  it "rejects words" do
    credit = Credit.new created_on: "some nonsense"
    credit.should_not be_valid
    credit.created_on.should be_nil
  end

  it "accepts good dates" do
    date = "2013-02-28"
    credit = Credit.new created_on: date
    credit.should be_valid
    credit.created_on.should == Date.parse(date)
  end
end

即使没有宝石,你也可以相当轻松地验证这一点,但这看起来像是一个方便的宝石。不要忘记运行发电机来完成安装。

如果您确实选择自行进行验证,则可能会遇到一些问题。

一种情况是,当您尝试将错误值粘贴到datedatetime列时,底层数据库的行为会有所不同;有些人在存储的价值和他们自动转换时更灵活。最好提前在Rails方面进行验证。

更大的问题是,在运行验证时,ActiveRecord已经尝试将值转换为与数据库字段类型匹配的类型。如果数据库中datecreated_on字段,ActiveRecord会将分配给created_on的每个值转换为Date对象。对于许多格式错误的日期,这将最终成为nil。在验证器中,您需要查看created_on_before_type_cast,它将是原始字符串。 ActiveRecord为每个DB列创建一个动态*_before_type_cast方法。您可以检查其格式并拒绝错误值。

我提到这些警告鼓励你坚持使用宝石。 :)