测试可变范围关联
Testing a variable scope association
我正在努力使我的测试稳健可靠,并且我一直在将一些复杂的查询和关联分解为更小的查询和关联,或者重构数据并将其移动到范围中。
鉴于以下 类:
class Item < ActiveRecord::Base
belongs_to :location
scope :in_location, ->(location) { where(location: location) }
scope :findable, ->(location, not_ids) {
in_location(location).where.not(id: not_ids)
}
end
class Container < ActiveRecord::Base
belongs_to :location
# THIS IS WHAT I WANT TO TEST
has_many :findable_items, ->(container) {
findable(container.location, container.not_findable_ids)
}, class_name: 'Item'
end
如何在不显着影响数据库的情况下测试这样的变量 has_many 关系?我知道我可以自己测试 Item.findable 方法;我感兴趣的是 container.findable_items 方法。
注意:正在测试的实际关联比这更复杂,并且需要相当广泛的设置;它是 运行 通过其他一些嵌套关联和范围。如果可能,我想避免这种设置,只是测试是否使用正确的值调用范围。
我的 Gemfile 的相关部分:
rails (4.2.3)
shoulda-matchers (2.6.2)
factory_girl (4.5.0)
factory_girl_rails (4.5.0)
rspec-core (3.3.2)
rspec-expectations (3.3.1)
rspec-its (1.2.0)
rspec-mocks (3.3.2)
rspec-rails (3.3.3)
我的项目中有 shoulda-matchers,所以我可以做基本的完整性测试:
it { should have_many(:findable_items).class_name('Item') }
但这失败了:
describe 'findable_line_items' do
let(:container) { @container } # where container is a valid but unsaved Container
let(:location) { @container.location }
it 'gets items that are in the location and not excluded' do
container.not_findable_ids = [1,2]
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids)
container.findable_items
end
end
此规范失败并出现以下错误:
1) Container findable_line_items gets items that are in the location and not excluded
Failure/Error: container.findable_items
NoMethodError:
undefined method `except' for nil:NilClass
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:158:in `block (2 levels) in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `block in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each_with_index'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `add_constraints'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:39:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:5:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:97:in `association_scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:86:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:423:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_proxy.rb:37:in `initialize'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `new'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `create'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:39:in `reader'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/builder/association.rb:115:in `pickable_items'
# ./spec/models/container_spec.rb:25:in `block (3 levels) in <top (required)>'
如果不实际设置满足所有要求的项目,您将如何通过此规范?
我最终采用了这样的解决方案:
describe 'findable_line_items' do
let(:container) { @container } # where container is a valid but unsaved Container
let(:location) { @container.location }
it 'gets items that are in the location and not excluded' do
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids).and_call_original
expect(container).to receive(:location).and_call_original
expect(container).to receive(:not_findable_ids).and_call_original
container.findable_items
end
end
发生的错误是在 ActiveRecord 关联设置中的某处;它试图在从我的项目存根返回的 nil
对象上实例化一个 ActiveRecord 数组。添加 .and_call_original
解决了该错误。
我真的不关心测试是否从此关联返回了正确的对象,因为该范围正在别处进行测试,只是正在使用该范围。在这种情况下,它仍然会访问数据库,但不会达到设置完整测试所需的 15 次。
我正在努力使我的测试稳健可靠,并且我一直在将一些复杂的查询和关联分解为更小的查询和关联,或者重构数据并将其移动到范围中。
鉴于以下 类:
class Item < ActiveRecord::Base
belongs_to :location
scope :in_location, ->(location) { where(location: location) }
scope :findable, ->(location, not_ids) {
in_location(location).where.not(id: not_ids)
}
end
class Container < ActiveRecord::Base
belongs_to :location
# THIS IS WHAT I WANT TO TEST
has_many :findable_items, ->(container) {
findable(container.location, container.not_findable_ids)
}, class_name: 'Item'
end
如何在不显着影响数据库的情况下测试这样的变量 has_many 关系?我知道我可以自己测试 Item.findable 方法;我感兴趣的是 container.findable_items 方法。
注意:正在测试的实际关联比这更复杂,并且需要相当广泛的设置;它是 运行 通过其他一些嵌套关联和范围。如果可能,我想避免这种设置,只是测试是否使用正确的值调用范围。
我的 Gemfile 的相关部分:
rails (4.2.3)
shoulda-matchers (2.6.2)
factory_girl (4.5.0)
factory_girl_rails (4.5.0)
rspec-core (3.3.2)
rspec-expectations (3.3.1)
rspec-its (1.2.0)
rspec-mocks (3.3.2)
rspec-rails (3.3.3)
我的项目中有 shoulda-matchers,所以我可以做基本的完整性测试:
it { should have_many(:findable_items).class_name('Item') }
但这失败了:
describe 'findable_line_items' do
let(:container) { @container } # where container is a valid but unsaved Container
let(:location) { @container.location }
it 'gets items that are in the location and not excluded' do
container.not_findable_ids = [1,2]
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids)
container.findable_items
end
end
此规范失败并出现以下错误:
1) Container findable_line_items gets items that are in the location and not excluded
Failure/Error: container.findable_items
NoMethodError:
undefined method `except' for nil:NilClass
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:158:in `block (2 levels) in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `block in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each_with_index'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `add_constraints'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:39:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:5:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:97:in `association_scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:86:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:423:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_proxy.rb:37:in `initialize'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `new'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `create'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:39:in `reader'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/builder/association.rb:115:in `pickable_items'
# ./spec/models/container_spec.rb:25:in `block (3 levels) in <top (required)>'
如果不实际设置满足所有要求的项目,您将如何通过此规范?
我最终采用了这样的解决方案:
describe 'findable_line_items' do
let(:container) { @container } # where container is a valid but unsaved Container
let(:location) { @container.location }
it 'gets items that are in the location and not excluded' do
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids).and_call_original
expect(container).to receive(:location).and_call_original
expect(container).to receive(:not_findable_ids).and_call_original
container.findable_items
end
end
发生的错误是在 ActiveRecord 关联设置中的某处;它试图在从我的项目存根返回的 nil
对象上实例化一个 ActiveRecord 数组。添加 .and_call_original
解决了该错误。
我真的不关心测试是否从此关联返回了正确的对象,因为该范围正在别处进行测试,只是正在使用该范围。在这种情况下,它仍然会访问数据库,但不会达到设置完整测试所需的 15 次。