2016-05-31 2 views
1

Я тестирую свои модели ActiveRecord в RSpec, и я пытаюсь ускорить мои тесты, просто создавая экземпляры вместо создания модели FactoryGirl, но ActiveRecord::Associations::CollectionProxy.include? возвращает true, когда я ожидаю false.Rails .include? возвращает true, когда это не должно

код Я тестирование этот метод в модели 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 

когда я создаю location_a и location_b с FactoryGirl тестовых проходов и include? возвращается false, но когда я создаю экземпляр location_a и location_b с этим кодом, тест не пройден, и в т.ч. удэ? возвращается true.

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

Печать locations показывает, что это CollectionProxy, содержащий location_b, и печать location аргумент показывает, что location_a, как с правильными свойствами. И, include? возвращает true, передан ли аргумент location или нет.

EDIT: некоторый дополнительный код.

Это код, чтобы определить тему ...

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 

нотабене Я попытался предоставить организацию конструктору (Location.new(name: 'London', organization: Organization.new)), но он не меняет результат.

+0

, пожалуйста, укажите свой заводской код. – Ilya

+0

Я не был уверен, что вы имели в виду определение предмета (я не использовал FG для создания темы в любой момент) или FactoryGirl для местоположения, но я предоставил оба в редактировании сообщения. – Squig

ответ

1

Я разработал решение. Я запишу это здесь, если у кого-то еще есть аналогичная проблема. Эти линии являются проблемой ...

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

before do 
    subject.locations = [location_b] 
end 

При использовании экземпляров модели, а не полноценные модели DB, сделанные FactoryGirl, ActiveRecord не обновляет изменения элементов в CollectionProxies. Что касается него, то locations всегда [location_a], даже если вы измените его на [location_b].

Решение состоит в том, чтобы присваивать свойства только один раз. То есть

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

before do 
    subject.locations = [location_b] 
end 

Установите местоположение в каждом контексте до блока в нужное место.

Я уверен, что это как-то связано со ссылками на Collection/CollectionProxy, но это вне меня.

4

CollectionProxy сравнивает модели их id с, так как обе записи являются новыми и имеют id == nil - include? возвращается true.

Чтобы иметь тест работает, вы должны сохранять модели в БД (использование create! и так далее)

+0

Я попытался предоставить 'id' в конструкторе Location, и это не помогло. Работает ли это только при сохранении моделей в БД? – Squig

+2

Это может быть неприятно писать тесты модели AR, которые используют только созданные экземпляры, но не сохраненные объекты. Довольно часто вы сталкиваетесь с ситуациями, когда вам нужен сохраненный объект (с идентификатором), которого вы не ожидали. Вы можете попробовать извлечь методы из модели и поместить их в другие классы, где вы можете протестировать их, не взаимодействуя с БД. – zetetic

+0

Это хорошая идея, спасибо. – Squig

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