Rspec 3 - как обрабатывать before_validation в тесте модели

В моей модели у меня есть метод before_validation:

class Post < ActiveRecord::Base
 before_validation :generate_url
 ...

 private

def generate_url
   return unless self.url.blank?
   year = self.published_at.class == ActiveSupport::TimeWithZone ? self.published_at.year : DateTime.now.year
   self.url = "#{year}/#{self.title.parameterize}"
end

rspec/модели/post.spec.rb

тестируя w rspec-rails (3.1.0) и factory_girl_rails (4.4.1), я получил spec/models/post_spec.rb для проверки модели Post и spec/factories/post.rb

проверочные тесты терпят неудачу из-за before_validation

 Post should require title to be set
 Failure/Error: it { is_expected.to validate_presence_of(:title) }
 NoMethodError:
   undefined method `parameterize' for nil:NilClass
 # ./app/models/post.rb:69:in `generate_url'
 # ./spec/models/post_spec.rb:20:in `block (2 levels) in <top (required)>'

с оператором отладки в методе generate_url я получаю себя как ноль ... так что кажется, что фабричный пост не принимается во внимание

спец/модели/post_spec.rb

require 'rails_helper'

RSpec.describe Post, :type => :model do
  it { is_expected.to validate_presence_of(:title) }
  it { is_expected.to ensure_length_of(:title).is_at_least(5) }
  it { is_expected.to validate_presence_of(:content) }
  it { is_expected.to ensure_length_of(:content).is_at_least(10) }
  it { is_expected.to validate_presence_of(:url) }
  it { is_expected.to validate_uniqueness_of(:url) }
  it { is_expected.to validate_presence_of(:published_at) }
end

спец/фабрики/post.rb

FactoryGirl.define do
  factory :post do
    user_id 1
    title "myTitle"
    content "myContent."
    published false
    published_at "2014-09-16 08:46:38"
  end
end
# note : attribute url is generated with before_validation

person Community    schedule 22.09.2014    source источник
comment
опубликуйте код generate_url mehtod и заполните тестовый код для получения подробного ответа. Вы должны либо заглушить generate_url, либо предоставить некоторые данные по умолчанию для публикации, чтобы generate_url работал правильно.   -  person dre-hh    schedule 22.09.2014
comment
данные предоставляются сообщению с factory/post.rb, если я не пропустил какие-либо дополнительные настройки, чтобы правильно прочитать их во время обработки спецификации?   -  person    schedule 22.09.2014


Ответы (2)


Получил, чтобы пропустить before_validation:

RSpec.describe Post, :type => :model do

  before{ Post.skip_callback(:validation, :before, :generate_url) }

  it { is_expected.to validate_presence_of(:user_id) }
  it { is_expected.to validate_presence_of(:title) }
  it { is_expected.to ensure_length_of(:title).is_at_least(5) }
  it { is_expected.to validate_presence_of(:content) }
  it { is_expected.to ensure_length_of(:content).is_at_least(10) }
  it { is_expected.to validate_presence_of(:url) }
  it { is_expected.to validate_uniqueness_of(:url) }
  it { is_expected.to validate_presence_of(:published_at) }
end

Вы также можете указать блок, чтобы проверка пропускалась только для блока, например:

RSpec.describe Post, :type => :model do

  Post.skip_callback(:validation, :before, :generate_url) do 
    it { is_expected.to validate_presence_of(:user_id) }
    it { is_expected.to validate_presence_of(:title) }
    it { is_expected.to ensure_length_of(:title).is_at_least(5) }
    it { is_expected.to validate_presence_of(:content) }
    it { is_expected.to ensure_length_of(:content).is_at_least(10) }
    it { is_expected.to validate_presence_of(:url) }
    it { is_expected.to validate_uniqueness_of(:url) }
    it { is_expected.to validate_presence_of(:published_at) }
  end
end
person Community    schedule 22.09.2014

ПРИМЕЧАНИЕ: self не равен нулю. self.title равен нулю

Согласно документу следует Спецификацию можно исправить, установив правильную тему, подобную этой

RSpec.describe Post, :type => :model do
  subject { FactoryGirl.create :post }
  it { is_expected.to validate_presence_of(:title) }
end

Однако я попробовал это, и ошибка все еще возникает. validate_presence_of просто игнорирует тему и сбрасывает ее на Post.new. Он всегда игнорирует ожидаемую вещь. Я бы сказал, что это ошибка. Позже проверим их код или хотя бы отправим сообщение о проблеме.

А пока просто делай это без дурака по-старому

RSpec.describe Post, :type => :model do
    describe #valiadations do
      let!(:post) {Post.new.tap{|p|p.valid?} }
      it "validated title" do
        expect(post.errors_on[:title.size]).to eq(1) 
      end 
    end
 end
person dre-hh    schedule 22.09.2014