DrSnipesMcGee21
DrSnipesMcGee21

Reputation: 169

Rspec model tests failing due to custom validation method not being found

For some reason my Rspec Model tests are failing for one of my models due to a custom validation method that is being called, but not found within the test. At least that's what I think is happening. This validation is triggered when the form is submitted to create a new Dinosaur in the app. Can anyone tell me why this may be happening and what a potential fix may be?

This is the failure error for all 4 tests:

Failure/Error: if cage.at_capacity?
     
     NoMethodError:
       undefined method `at_capacity?' for nil:NilClass

Model/dinosaur.rb

class Dinosaur < ApplicationRecord
    belongs_to :cage
    validates :name, :species, :diet_type, :cage_id, presence: true
    validates_uniqueness_of :name
    validate :is_cage_at_capacity
    validate :is_cage_powered_down
    validate :cage_contains_diet_mismatch

=begin
    def set_cage(c)

        return false if c.at_capacity?
        cage = c

    end

    def move_dino_to_powered_down_cage(c)

        return false if c.is_powered_down?
        cage = c

    end
=end

    def is_herbivore?
        return diet_type == "Herbivore"
    end

    def is_carnivore?
        return diet_type == "Carnivore"
    end

    def is_cage_powered_down
        if cage.is_powered_down?
            errors.add(:cage_id, "Chosen cage is powered down. Please choose another cage!")
        end
    end

    def is_cage_at_capacity
        if cage.at_capacity?
            errors.add(:cage_id, "Chosen cage is full. Please choose another cage!")
            end
    end

    def cage_contains_diet_mismatch
        if cage.has_carnivore == true and is_herbivore?
            errors.add(:cage_id, "Chosen cage contains carnivores! This dinosaur will be eaten!")
        else
            if cage.has_herbivore == true and is_carnivore?
                errors.add(:cage_id, "Chosen cage contains herbivores! This dinosaur will eat the others!")
            end
        end
    end


end

spec/models/dinosaur_spec.rb

require 'rails_helper'

describe Dinosaur, type: :model do

    it "is valid with valid attributes" do
        dinosaur = Dinosaur.new(name:"Yellow", species:"Tyrranosaurus", diet_type:"Carnivore", cage_id: 7)
        expect(dinosaur).to be_valid
    end

    it "is not valid without a name" do
        dinosaur = Dinosaur.new(name: nil)
        expect(dinosaur).to_not be_valid
    end
    it "is not valid without a max capacity" do
        dinosaur = Dinosaur.new(species: nil)
        expect(dinosaur).to_not be_valid
    end
    it "is not valid without a power status" do
        dinosaur = Dinosaur.new(diet_type: nil)
        expect(dinosaur).to_not be_valid
    end
end

Upvotes: 0

Views: 809

Answers (2)

Ivan Garcia
Ivan Garcia

Reputation: 164

It seems that when the execution of the program reaches the is_cage_at_capacity method the cage is not set, actually the error has a clue: undefined method 'at_capacity?' for nil:NilClass this means that you are trying to send the method at_capacity? to a nil object.

So, I think some options to fix it will be to make sure a cage is associated with the Dinosaur when created or to add a guard clause to the is_cage_at_capacity method, something like this:

def is_cage_at_capacity
  if cage.nil?
    errors.add(:cage_id, "There is not a cage associated with the dinosaur")
  end

  if cage.at_capacity?
    errors.add(:cage_id, "Chosen cage is full. Please choose another cage!")
  end
end

Upvotes: 0

yzalavin
yzalavin

Reputation: 1836

Why this happening?

When you call method valid? all validations are triggered. At least, is_cage_at_capacity calls dinosaur.cage.at_capacity?. However, Dinosaur.new(diet_type: nil) does not have any cage so the exception is raised.

How can you fix it?

The simplest way would be to add a cage in your tests:

cage = Cage.new
dinosaur = cage.build_dinosaur(params)

It could be quite repetetive to build all these objects every time, so consider using FactoryBot with associations.

When testing validations it is more precise to test an expected error instead of the whole object state. Check this.

For built-in validations (e.g. presence, uniqueness) better use shoulda-matchers.

Upvotes: 2

Related Questions