Rails。包括?当它不应该

时间:2016-05-31 15:26:21

标签: ruby-on-rails ruby rspec

我在RSpec中测试我的ActiveRecord模型,我试图通过实例化模型而不是创建FactoryGirl模型来加速我的测试,但ActiveRecord::Associations::CollectionProxy.include?正在返回true当我期待false时。

我测试的代码是Schedule模型中的这个方法,它传递了Location模型实例的参数...

def available_at_location(location)
  locations.include?(location)
end

测试是......

before do
  subject.locations = [location_b]
end

it 'returns false' do
  result = subject.available_at_location(location_a)

  expect(result).to be(false)
end

当我使用FactoryGirl创建location_alocation_b时,测试通过,include?返回false,但是当我实例化location_alocation_b时使用此代码,测试失败并包括?返回true

let(:location_a) { Location.new(name: 'London') }
let(:location_b) { Location.new(name: 'York') }

打印locations表示它是包含location_b的CollectionProxy,打印location参数显示它是location_a,两者都具有正确的属性。而且,include?返回true是否传递location参数。

编辑:一些额外的代码。

这是定义主题的代码......

subject { described_class.new(locations: [location_a]) }

这是FactoryGirl位置工厂的代码......

require 'faker'

FactoryGirl.define do
  factory :location do
    name { Faker::Company.name }
    address { Faker::Address.street_address }
    city { Faker::Address.city }
    zipcode { Faker::Address.zip_code }
    landline { Faker::PhoneNumber.phone_number }
    association :organization
  end
end

N.B。我尝试过向构造函数(Location.new(name: 'London', organization: Organization.new))提供一个组织,但它并没有改变输出。

2 个答案:

答案 0 :(得分:4)

CollectionProxy会根据id对模型进行比较,因为这两个记录都是新的,并且id == nil - include?会返回true

要让您的测试正常工作,您必须将模型保存到db(使用create!等等)

答案 1 :(得分:1)

我已经找到了解决方案。我会在这里记录这个,以防其他人有类似的问题。这些问题是......

subject { described_class.new(locations: [location_a]) }

before do
  subject.locations = [location_b]
end

当使用模型实例而不是FactoryGirl制作的完整数据库模型时,ActiveRecord不会更新CollectionProxies中项目的更改。即使您将项目更改为locations[location_a]总是[location_b]

解决方案是仅分配属性一次。即。

subject { described_class.new(locations: []) }

before do
  subject.locations = [location_b]
end

将阻止前的每个上下文中的位置设置为所需位置。

我确信这与Collection / CollectionProxy的引用有关,但它超出了我的范围。