Search code examples
ruby-on-railsrspecrspec-railsshoulda

RSpec example not working with before_validation


I have a fairly simple model being saved, but am getting RSpec failures that I cannot find the solution to. I am also using the shoulda gem.

CharacterSheet model:

class CharacterSheet < ActiveRecord::Base
  validates :character_name, :player_name, :strength, :strength_modifier, presence: true

  before_validation :calculate_strength_modifier, on: :create

  def calculate_strength_modifier
    self.strength_modifier = ((self.strength - 10)/2).floor
  end

end

RSpec Example:

RSpec.describe CharacterSheet, type: :model do

  let(:character_sheet) { CharacterSheet.new(character_name: "Test Character",
                                                player_name: "Michael",
                                                   strength: 18) }

  describe "attributes" do

    it { expect(character_sheet).to validate_presence_of :character_name }
    it { expect(character_sheet).to validate_presence_of :player_name }
    it { expect(character_sheet).to validate_presence_of :strength }
    it { expect(character_sheet).to validate_presence_of :strength_modifier }

    it "saves attributes" do
      character_sheet.save!
      expect(character_sheet).to be_valid
    end

  end
end

These are the failures I am getting:

Failures:

  1) CharacterSheet attributes should require strength to be set
     Failure/Error: it { expect(character_sheet).to validate_presence_of :strength }
     NoMethodError:
       undefined method `-' for nil:NilClass

  2) CharacterSheet attributes should require strength_modifier to be set
     Failure/Error: it { expect(character_sheet).to validate_presence_of :strength_modifier }
       Expected errors to include "can't be blank" when strength_modifier is set to nil,
       got no errors

If I create a record in the rails console manually, it looks correct. Just the tests are failing.

Additionally, if I remove the before_validation call. The only thing that fails is the "saves attributes" example as expected.


Solution

  • ok, first you have to understand the the validate_presence_of matcher... sets the value of that attribute to nil... and tests that you get an error.

    Think of what that means for your before-validation. You have nothing in strength... then before you get to the validation the before-validation trigger is triggered... and you try to take 10 away from nothing and it explodes.

    My bet is that you should put a test in there to make sure that doesn't do silly things. Eg:

    def calculate_strength_modifier
      self.strength_modifier = ((self.strength - 10)/2).floor if self.strength.present?
    end