这些天我在 Shoulda 和 Rspec 之间摇摆不定。我已经阅读并使用了相当多的 RSpec,但与 Shoulda 相比并没有那么多。我发现 Shoulda 的单行断言更易于阅读,并且测试看起来更清晰。但是当我不知道如何在 Shoulda 中编写特定断言时,我切换到 RSpec。不过也不是很开心。
所以这就是我今天所做的。我为我的模型编写了一些自定义验证 Course
.类(class)有 start_date
和一个 end_date.
围绕它有一些规则。
start_date
和 end_date
都是强制性的 start_date
不能晚于今天 end_date
不能在 start_date
之前我知道那里有一些安静的 gem 可以为我做到这一点。但是因为我是新手,所以我认为自己做并边走边学可能是个好主意。
所以这就是我的模型的样子
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
以下是我的 course_spec
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 不为零?
验证在 View 中工作正常。我的意思是我得到正确的验证错误取决于我输入的数据类型。但是我测试失败了。我已经研究了一段时间,但无法弄清楚我到底做错了什么。
最佳答案
我认为您可以通过以下两种方式之一解决此问题:
要么你需要放置你date = DateTime.now.to_date
进到before(:each)
堵塞。
context 'validations' do
before(:each) { 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
或者您可以使用 rails 日期助手。
context 'validations' do
it { should allow_value(Date.today).for(:start_date) }
it { should_not allow_value(10.days.ago).for(:start_date) }
it { should allow_value(10.days.from_now).for(:end_date)}
it { should_not allow_value(10.days.ago).for(:end_date)}
end
关于ruby-on-rails - Rails 3 自定义验证和 shoulda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8558369/