Search code examples
ruby-on-railsunit-testingrspecfactory-botfaker

Rspec testing with FactoryBot - ActiveRecord::InvalidRecord Error


While testing my model i am using data generated by FactoryBot. Inside model, I have mentioned validation for out_of_print as True. While Running the test case it says can't accept the nil value.

'Book model code'

class Book < ApplicationRecord
  belongs_to :supplier
  belongs_to :author
  has_many :reviews

  validates :price, :year_published,:views, presence: true
  validates :title, presence: true, uniqueness: true
  validates :out_of_print,presence: true

  scope :in_print, -> { where(out_of_print: false) }
  scope :out_of_print, -> { where(out_of_print: true) }
  scope :old, -> { where('year_published < ?', 50.years.ago )}
  scope :out_of_print_and_expensive, -> { out_of_print.where('price > 500') }
  scope :costs_more_than, ->(amount) { where('price > ?', amount) }
end 

"Factroy for book"

FactoryBot.define do
  factory :book do
    title { Faker::Name.name}
    year_published { Faker::Number.within(range: 1800..2020) }
    price { "9.99" }
    out_of_print {false}
    views { Faker::Number.between(from: 100, to: 1000) }
    association :author
    association :supplier
  end
end

"Testing code"

  describe 'create' do
    it "should create a valid book" do
     author = create(:author)
     # author.save
     supplier = create(:supplier)
     # supplier.save
     # book = build(:book,supplier: supplier,author: author)
     book = create(:book,supplier: supplier,author: author)

     # book.save
     # puts(book.errors.full_messages)
     expect(book.save).to eq(true)
    end
   end
 end

"Error"

Failures:

 1) Book create should create a valid book
 Failure/Error: book = create(:book,supplier: supplier,author: author)
 
 ActiveRecord::RecordInvalid:
   Validation failed: Out of print can't be blank

Solution

  • Validating presence with presence: true on boolean fields will always require the value to be true.

    presence validation uses blank? to check if the value is either nil or a blank string.

    But for booleans:

    true.blank? => false
    false.blank? => true
    

    Validating boolean fields should look like this:

    validates :out_of_print, inclusion: [true, false]
    # or
    validates :out_of_print, exclusion: [nil]
    

    Docs.