我在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_a
和location_b
时,测试通过,include?
返回false
,但是当我实例化location_a
和location_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)
)提供一个组织,但它并没有改变输出。
答案 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的引用有关,但它超出了我的范围。