2015-09-02 11 views
0

Я пытаюсь сделать мои тесты прочными и действительно прочными, и я разбил некоторые сложные запросы и ассоциации на более мелкие, или рефакторинг и перемещение данных в области.Тестирование ассоциации с переменной переменной

Учитывая следующие классы:

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)>' 

Как вы можете получить эту спецификацию, фактически не создав Предмет, соответствующий всем требованиям?

+0

Исключение базы данных во многих случаях является хорошей идеей, но не здесь, поскольку оба области и отношения в рельсах неразрывно связаны с ORM/db. Даже если возможно, какое значение даст ваш тест на самом деле, если вы выполняете настоящую функциональность? – max

+0

Я тестирую «фактическую» функциональность в тесте в item_spec; Мне не нужно проверять, что область действия здесь, просто, что она называется. – guiniveretoo

ответ

0

я в конечном итоге происходит с решением, как это:

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; он пытался создать экземпляр массива ActiveRecord на объекте nil, который возвращался из моего заглушки Item. Добавление .and_call_original решило эту ошибку.

Мне не нужно проверять, что правильные объекты возвращаются из этой ассоциации, так как эта область проверяется в другом месте, просто используется область. Он по-прежнему попадает в базу данных в этом сценарии, но не в 15 раз, которые потребуются для установки полного теста.

 Смежные вопросы

  • Нет связанных вопросов^_^