2011-12-19 3 views
4

В настоящее время происходит размах между Shoulda и Rspec. Я читал и играл вокруг честного с RSpec, но не так много с Shoulda. Я считаю, что утверждения в одной строке легче всего читать, и тест выглядит более чистым. Но когда я не могу понять, как написать конкретное утверждение в Shoulda, я переключусь на RSpec. Однако это не очень радует.Rails 3 custom validation и shoulda

Итак, вот что я сделал сегодня. Я написал некоторые пользовательские проверки для моей модели 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 

И следующий мой 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 

Теперь, прежде чем я написал последний «it» block using Rspec У меня было что-то подобное в моем контексте проверки

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)"] 

не уверен, что я делаю неправильно здесь. Является ли мой пользовательский код проверки неправильным или мне нужно что-то настроить, прежде чем я запустил последнее утверждение, чтобы start_date не был нулем при тестировании end_date?

Валидации отлично работают на вид. Я имею в виду, что получаю правильные ошибки проверки в зависимости от типа данных, которые я вводил. Но тест не проходит. Я смотрел на это какое-то время, но не могу понять, что именно я делаю неправильно.

ответ

0

@nickgrim уже ответил на вопрос, но я хочу добавить комментарий. Точка describe и it предназначена для поощрения предложений, которые начинаются со слов «описать» и «это». В вашем примере у вас есть это:

it " end date should not be before course start date" do 
    # ... 

«это конец даты ....» не является предложением. Пожалуйста, напишите, что, как что-то вроде:

it "validates that end date should be >= start date" do 
+0

Спасибо за ввод, но я подумал, что когда шаги распечатываются на консоли, они должны делать читаемые предложения. поэтому мой вывод на консоли, когда я запускаю свою спецификацию, - это что-то вроде этого. Курс дата окончания не должна быть до даты начала курса. валидации должно требовать, чтобы имя было задано. должен требовать установить курс курса ... 'Что вы предполагая, что это правильно для тех, кто читает спецификацию. Не знаю, какой подход следует придерживаться сейчас. Есть предположения? – MMinhas

+0

С моей точки зрения, мы должны работать, чтобы сделать спецификацию и консольный вывод доступными для чтения. Но если вы не можете иметь оба (вид, почему), то вывод консоли более важен, если вы используете вывод в режиме подробного описания. Если вы используете только точки, то спецификация важнее. Но я определенно хотел бы видеть хороший читаемый вывод консоли, особенно когда тесты терпят неудачу :) –

3

Я думаю, вы могли бы решить это в одном из двух способов два:

Либо вам нужно место, куда вы 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 

Или вы можете использовать помощников по рельсам.

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