FactoryBot - определите фабрику, которая предоставляет допустимые значения по умолчанию для различных переопределений - PullRequest
0 голосов
/ 05 октября 2018

A Sale принадлежит Item и Price.Item принадлежит Item_Type, а Price также относится к ItemType.Для любого Sale s у нас должно быть s.item.item_type == s.price.item_type, иначе база данных находится в недопустимом состоянии.Кроме того, Sale validates_presence_of :item, :price.

Я хотел бы построить Sale экземпляров, используя FactoryBot.

FactoryBot.define do
  sequence :item_type_name do |n|
    "type#{n}"
  end

  factory :item_type do
    name {generate(:item_type_name)}
  end

  factory :item
    item_type
  end

  factory :price do     
    item_type
  end

  factory :sale do
    item
    price
  end
end

sale = build(:sale)

Проблема: это приводит к продаже с конфликтующими item_types

sale.item.item_type != sale.price.item_type

Попытка исправить:

factory :sale do
  item
  price
  after(:build) do |sale|
    if (sale.item.item_type != sale.price.item_type)
      sale.price = build(:price, item_type: sale.item.item_type)
    end
  end
end

Это работает нормально, когда вы строите продажу без переопределений

sale = build(:sale)

, но дает нежелательное поведение, когда предоставляется переопределение price иitem не равно:

myPrice = build(:price)
sale = build(:sale, price: myPrice) # oops! myPrice is overwritten

Требуемое поведение выглядит следующим образом

describe 'sale_factory' do
    context 'no overrides provided' do
        it 'makes an item and price with matching item_types' do
            sale = build(:sale)
            expect(sale.item.item_type).to eq sale.price.item_type
        end
    end
    context 'item override provided' do
        it 'makes a price whose item_type matches that of item override' do
            item = build(:item)
            sale = build(:sale, item: item)
            expect(sale.item).to eq item
            expect(sale.price.item_type).to eq item.item_type
        end
    context 'price override provided' do
        it 'makes an item whose item_type matches that of price override' do
            price = build(:price)
            sale = build(:sale, price: price)
            expect(sale.price).to eq price
            expect(sale.item.item_type).to eq price.item_type
        end
    context 'price and item overrides provided' do
        it 'makes a sale using provided overrides if item_types do not conflict' do
            item = build(:item)
            price = build(:price, item_type: item.item_type)
            sale = build(:sale, item: item, price: price)
            expect(sale.item).to eq item
            expect(sale.price).to eq price
        end

        it 'raises an error if item_types conflict' do
            item_type_1 = build(:item_type)
            item_type_2 = build(:item_type)
            item = build(:item, item_type: item_type_1)
            price = build(:price, item_type: item_type_2)
            expect{build(:sale, item: item, price: price)}
                .to raise_error "conflicting item types"
        end
    end
end

Как мне добиться желаемого поведения?

...