2016-05-31 5 views
0

Рассмотрим две модели:FactoryGirl Как создать экземпляр, который создается объединением на обратный вызов

class User < ActiveRecord::Base 

    has_one :book 

    after_create :create_book 
end 

class Book < ActiveRecord::Base 
    belongs_to :user 

    validate_uniqueness :user_id 
end 

Каждый пользователь может иметь и может иметь только одну книгу. Потом я два завода определен в моей спецификации:

factory :user do 
end 

factory book do 
    user 
end 

Тогда вот вопрос, когда я пишу тест для Book, я хотел бы создать запись book1 (назовем его) для Book, когда я использую FactoryGirl.create(:book). Он создаст экземпляр Book, а затем попытается создать ассоциацию, определенную user. После создания пользователя after_create является триггером, а book2 создан для user. Затем он пытается связать book1 с user и блокирован ассоциацией единства.

Теперь я использую book = FactoryGirl.create(:user).book. Это лучший/правильный способ сделать это? Я думаю, что это так интуитивно понятно, поскольку я тестирую Book, я думаю, было бы лучше всего иметь book = FactoryGirl.create(:book)

Большое спасибо.

ответ

1

Я думаю, мы можем использовать trait для этого. Вот пример:

завод

factory :user do 
    # Your config here 

    # Use trait 
    trait :without_book do 
    after(:build) do |user| 
     allow(user).to receive(:create_book).and_return true 
    end 
    end 

    trait :with_book do 
    allow(user).to receive(:create_book).and_call_original 
    end 

    transient do 
    # Use this by default but don't use this line also works 
    # because we create book in the normal behavior 
    with_book 
    end 
end 

Spec

context 'test user without book' do 
    let(:user) { FactoryGirl.create(:user, :without_book) 

    it 'blah blah' do 
    end 
end 

context 'test user with book' do 
    let(:user) { FactoryGirl.create(:user, :with_book) 
    # Or simply use this, because :with_book is default 
    # let(:user) { FactoryGirl.create(:user) 

    it 'blah blah' do 
    end 
end 

Btw, как вы видите, я использую метод заглушки на allow(user).to receive(:create_book).and_return true, в основном, этот метод полезности исходит из rspec-mock, и нам нужна эта конфигурация, чтобы сделать ее доступной на заводе:

спецификации/rails_helper.rb

FactoryGirl::SyntaxRunner.class_eval do 
    include RSpec::Mocks::ExampleMethods 
end 

В идеале, вы можете обрабатывать create или not create книгу с помощью trait для пользователя, он будет легче моделировать сценарий!

+0

Отличная идея. Но я получил 'undefined метод' and_return 'для # (NoMethodError) 'пробует ваши образцы, я не знаю почему. Но я обойду с помощью 'after (: build) {| user | user.class.skip_callback (: create,: after,: create_book_for_user)} ' – larryzhao

+0

Вы включаете' include RSpec :: Mocks :: ExampleMethods' в rails_helper.rb –

+0

Да, извините, я пропустил это сначала. Я просто пытаюсь это сделать, с 'include RSpec :: Mocks :: ExmpleMethods' в моем' rails_helper.rb'. Я все еще получаю 'NoMethodError: undefined method' allow 'для # ' – larryzhao

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

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