由于未找到自定义验证方法,Rspec 模型测试失败

问题描述

由于某种原因,我的一个模型的 Rspec 模型测试失败,原因是正在调用自定义验证方法,但未在测试中找到。至少这是我认为正在发生的事情。当提交表单以在应用程序中创建新的恐龙时,会触发此验证。谁能告诉我为什么会发生这种情况以及可能的修复方法是什么?

这是所有 4 个测试的失败错误

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

模型/恐龙.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

解决方法

为什么会这样?

当您调用方法 valid? 时,所有验证都会被触发。至少,is_cage_at_capacity 会调用 dinosaur.cage.at_capacity?。但是,Dinosaur.new(diet_type: nil) 没有任何笼子,因此引发了异常。

如何解决?

最简单的方法是在测试中添加一个笼子:

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

每次构建所有这些对象可能会非常重复,因此请考虑使用 FactoryBot with associations

在测试验证时,测试预期错误而不是整个对象状态会更精确。检查this

对于内置验证(例如存在性、唯一性),最好使用 shoulda-matchers

,

貌似当程序执行到了 is_cage_at_capacity 方法没有设置笼子的时候,其实这个错误是有线索的:undefined method 'at_capacity?' for nil:NilClass 这意味着你正在尝试发送方法 {{ 1}} 到一个 nil 对象。

所以,我认为修复它的一些选择是确保笼子在创建时与恐龙相关联,或者在 at_capacity? 方法中添加一个保护子句,如下所示:

is_cage_at_capacity