【发布时间】:2011-12-19 07:36:05
【问题描述】:
这些天我在 Shoulda 和 Rspec 之间摇摆不定。我已经阅读并玩过 RSpec 的一些内容,但对于 Shoulda 则没有那么多。我发现 Shoulda 的单行断言更易于阅读,并且测试看起来更清晰。但是,当我无法弄清楚如何在 Shoulda 中编写特定的断言时,我会切换到 RSpec。虽然不是很高兴。
这就是我今天所做的。我为我的模型Course 编写了一些自定义验证。一门课程有一个start_date 和一个end_date. 围绕它有一些规则。
-
start_date和end_date都是必填项 -
start_date不能迟于今天 -
end_date不能在start_date之前
我知道那里有一些安静的宝石可以为我做到这一点。但是因为我是新手,所以我认为自己做这件事并边做边学可能是个好主意。
这就是我的模型的样子
class Course < ActiveRecord::Base
belongs_to :category
has_many :batches, :dependent => :destroy
accepts_nested_attributes_for :batches, :reject_if => lambda {|a| a[:code].blank?}, :allow_destroy => true
has_and_belongs_to_many :students, :uniq => true
validates_presence_of :name, :course_code, :total_seats
validates_uniqueness_of :category_id, :scope => [:name, :course_code]
validates :start_date, :presence => true, :course_start_date=>true
validates :end_date, :presence => true, :course_end_date=>true
end
我的自定义验证如下
class CourseEndDateValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if object.errors[attribute].blank? && object.errors[:start_date].blank?
if value < object.start_date
object.errors[attribute] << "cannot be later than start date"
end
end
end
end
class CourseStartDateValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if object.errors[attribute].blank?
if value < DateTime.now.to_date
object.errors[attribute] << "cannot be later than today"
end
end
end
end
以下是我的课程规范
require 'spec_helper'require 'date'
describe Course do
context 'validations' do
it { should validate_presence_of(:name)}
it { should validate_presence_of(:course_code)}
it { should validate_presence_of(:start_date)}
it { should validate_presence_of(:end_date)}
it { should validate_presence_of(:total_seats)}
date = DateTime.now.to_date
it { should allow_value(date).for(:start_date) }
it { should_not allow_value(date - 10 ).for(:start_date) }
it {should allow_value(date + 10).for(:end_date)}
end
context 'associations' do
it { should belong_to(:category)}
it { should have_many(:batches).dependent(:destroy)}
it { should have_and_belong_to_many(:students) }
end
it " end date should not be before course start date" do
course = FactoryGirl.build(:course, :end_date=>'2011-12-10')
course.should be_invalid
end
end
现在,在我使用 Rspec 编写最后一个“it”块之前,我的验证上下文中有类似的内容
context 'validations' do
it { should validate_presence_of(:name)}
it { should validate_presence_of(:course_code)}
it { should validate_presence_of(:start_date)}
it { should validate_presence_of(:end_date)}
it { should validate_presence_of(:total_seats)}
date = DateTime.now.to_date
it { should allow_value(date).for(:start_date) }
it { should_not allow_value(date - 10 ).for(:start_date) }
it { should allow_value(date + 10).for(:end_date)}
it { should_not allow_value(date - 10).for(:end_date)} # <-------------------
end
我得到了以下失败
Failures:
1) Course validations
Failure/Error: it { should_not allow_value(date - 10).for(:end_date)}
Expected errors when end_date is set to Fri, 9 Dec 2011, got errors: ["name can't be blank (nil)", "course_code can't be blank (nil)", "total_seats can't be blank (nil)", "start_date can't be blank (nil)"]
我不确定我在这里做错了什么。是我的自定义验证代码不正确还是我需要在运行最后一个断言之前设置一些东西,以便在测试 end_date 时 start_date 不为零?
验证在视图中工作正常。我的意思是,根据我输入的数据类型,我会得到正确的验证错误。但是我的测试失败了。我已经看了一段时间了,但无法弄清楚我到底做错了什么。
【问题讨论】:
标签: ruby-on-rails validation rspec2 shoulda