迭代不适用于rspec / guard的自定义验证轨道 - 测试不通过

时间:2014-12-18 18:06:54

标签: ruby-on-rails ruby validation rspec

所以,我写了这个自定义验证方法:

    class MedicalDegree < ActiveRecord::Base
      extend Schools

      ...


      validate :validate_awarded_by_based_on_medical_school_table

      ...

       def validate_awarded_by_based_on_medical_school_table
        valid_awarded_by_values = MedicalDegree.medical_schools

        if valid_awarded_by_values.empty?
          error_msg = "the list was empty"
          errors.add(:awarded_by, error_msg)
        end

        unless valid_awarded_by_values.include?(awarded_by)
          error_msg = "is not a valid medical school"
          errors.add(:awarded_by, error_msg)
          errors.add(:awarded_by, valid_awarded_by_values)
        end
      end
    end

使用medical_schoolsSchools模块中的models/concerns函数:

module Schools
  extend ActiveSupport::Concern
  def medical_schools
    schools_list = MedicalSchool.all
    valid_awarded_by_values = []
    schools_list.each do |school|
      valid_awarded_by_values << school.name
    end

    valid_awarded_by_values
  end
end

其中MedicalSchool是模型名称,应引用medical_schools域表,其中包含所有有效医学院的名称。

在rails控制台中,此方法可以正常工作,验证也是如此 - 但是,在rspec中,似乎除了 schools_list.each块之外的所有都会运行,就像在我的测试

it "is valid with all attributes filled" do
    credential = build(:medical_degree)
    credential.valid?
    expect(credential).to be_valid
  end

Rspec返回错误:

Failure/Error: expect(credential).to be_valid
       expected #<MedicalDegree id: nil, degree_type: "Osteopathic", awarded_by: "Midwestern University Arizona College of Osteopath...", date_awarded: "2001-01-28", created_at: nil, updated_at: nil> to be valid, but got errors: Awarded by the list was empty, Awarded by is not a valid medical school, Awarded by []

我无法弄清楚为什么我的代码在任何地方工作但在rspec测试中,以及为什么只有.each块无法执行(因此valid_awarded_by_values的数组仍为空)。我还尝试将medical_schools方法的代码放在验证方法本身中,但是也无法运行.each块,并且似乎只运行了相等语句和if/unless语句。我真的很喜欢帮助弄清楚我的代码是不是问题,或者只是rspec,以及如何解决这个问题!

编辑:

如果数组本身是在medical_schools方法中定义的,例如

,它就可以正常工作

schools_list = ['school01','school02','school03'...]

因为它是我之前的自定义验证(然后我不需要迭代块)。当我决定使用域表来代替值并将其用于验证时,整个问题就开始了。

编辑01:

我开始相信运行自定义验证的rspec存在问题。在rails控制台中,我的验证工作完美,但在rspec中,与MedicalSchool模型相关的任何内容都为空(MedicalSchool.pluck(:name)返回一个空列表,尽管数据库中有许多条目,如做了我的迭代(我现在看到这不是最好的方法。)

我还被告知,如果我只想检查数据库中的值,我可以使用MedicalSchool.find_by(awarded_by) - 但尽管我正在测试的值是数据库表中的值,但在rspec中MedicalSchool.find_by会返回nil

1 个答案:

答案 0 :(得分:0)

Schools.medical_schools的结果基于查询MedicalSchool.all,类似于

SELECT * FROM medical_schools

因此它需要数据存在于数据库中,然后显示对此进行验证。现在,在您的测试期间,可能会发生您没有在数据库中记录任何医学院,然后MedicalDegree将无效的情况。这就是"Awarded by the list was empty"消息存在的原因。

您可以创建一所医学院,然后在测试其有效性之前为该学位指定名称。如果您使用FactoryGirl或其他工厂助手,可以使用它来帮助您。

我建议您不要根据名称或其他任意值来关联数据库,因为当需要更新其中一个值时,您也需要更新另一个表。更好的解决方案是medical_school_id,然后this documentation中描述的belongs_to关联。这也将使您更容易使用您的工厂库,至少对于您能够编写的工厂女孩​​来说

factory :medical_degree do
  association :medical_school
end

但是,当您只想获取模型的给定字段的列表时,您可以使用.pluck所述here

MedicalSchools.pluck(:name)