【问题标题】:RSpec has_many through #<ActiveRecord::Associations::CollectionProxy>RSpec has_many 通过#<ActiveRecord::Associations::CollectionProxy>
【发布时间】:2018-03-02 17:05:21
【问题描述】:

我有一个这样的关系模型:

class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end

我需要创建一个有很多患者的医师,对吗? 等等我的测试:

let!(:physician) { create(:physician) }
let!(:patients) { create_list(:patients, 2) }

我这样做了:

before { physician.patients << patients }

我想用这个测试生成的json

expect(physician.as_json).to eq({
  "id" => physician.id,
  "name" => physician.name,
  "patients" => physician.patients
})

我期待它会通过,但因为这个#&lt;ActiveRecord::Associations::CollectionProxy&gt;而失败了

我使用 binding.pry 进行了检查:

physician.patients == patients 结果是true

您介意帮助我吗,我是不是遗漏了什么?

【问题讨论】:

  • physician.patients 是记录的集合。它不等于预期的 json 数据。有多种写法,但基本上你的测试是错误的——你需要以某种方式定义预期结果应该是的 json 格式
  • #as_json 尽管名称返回一个可序列化的散列 - 而不是 JSON。否则你的评论会出现在@TomLord
  • 谢谢你@TomLord 我能够用你所有的 cmets 解决我的问题。
  • 以及 @max 用于阐述和澄清 Tom Lord 的评论。我相信我想出的解决方案来自你们的 cmets

标签: ruby-on-rails ruby activerecord rspec associations


【解决方案1】:

要将医生和患者联系起来,只需将密钥传递给create_list

let!(:patients) { create_list(:patients, 2, physician: physician ) }

或者您可以将其声明为:

let(:physician) { create(:physician, patients: build_list(patients: 2)) }

但是正如@TomLord 所提到的,测试本身仍然被破坏。您需要测试生成的散列 - 因为包含关联会导致它被转换为序列化散列:

{
  "id" => 1,
  "name" => "Dr Suess",
  "patients" => [
     {
        "id" => 1,
        "name" => "The Cat in The Hat"
     },
     {
        "id" => 2,
        "name" => "The Grinch"
     },
  ]
}

使用eq 测试准确的输出并不是最优的,因为对序列化的每次更改都会破坏测试。相反,您可以使用 include matcher 指定必须存在的内容:

describe '#as_json' do
   let!(:physician) { create(:physician) }
   let!(:patients) { create_list(:patients, 2) }
   subject(:serialized) { physician.as_json } 

   it { should include({
        "id" => physician.id,
        "name" => physician.name
   }) }
   it "includes the patients" do
      expect(serialized["patients"].length).to eq patients.length
      expect(serialized["patients"]).to include patients.first.as_json
      expect(serialized["patients"]).to include patients.last.as_json
   end
end

除非您已覆盖 as_json 方法,否则此规范应该会失败,因为您需要明确包含与 physician.as_json(include: :patients) 的关联。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 2014-04-26
相关资源
最近更新 更多