FactoryBot-定义一个工厂,为不同的替代提供有效的默认值

时间:2018-10-05 16:43:08

标签: ruby-on-rails ruby rspec factory-bot

Sale属于ItemPriceItem属于Item_Type,而Price也属于ItemType。对于任何Sale s,我们应该有s.item.item_type == s.price.item_type,否则数据库处于无效状态。此外,Sale validates_presence_of :item, :price

我想使用FactoryBot构建Sale实例。

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

如何实现所需的行为?

0 个答案:

没有答案