Rspec 3 - 如何在模型测试中处理before_validation

4 rspec-rails ruby-on-rails-4 factory-bot

在我的模型中,我有一个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
Run Code Online (Sandbox Code Playgroud)

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)>'
Run Code Online (Sandbox Code Playgroud)

使用generate_url方法中的调试语句,我得到自己为nil ...所以似乎工厂的帖子没有被考虑在内

规格/型号/ 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
Run Code Online (Sandbox Code Playgroud)

规格/工厂/ 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
Run Code Online (Sandbox Code Playgroud)

小智 6

得到它跳过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
Run Code Online (Sandbox Code Playgroud)

您还可以提供一个块,以便仅跳过块的验证,如下所示:

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
Run Code Online (Sandbox Code Playgroud)