Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton factories in factory_girl/machinist?

Is there some configuration in a factory of factory girl/machinist that forces it to create objects with the same factory name just once during test case and return the same instance all the time? I know, i can do something like:

def singleton name
    @@singletons ||= {}
    @@singletons[name] ||= Factory name
end
...
Factory.define :my_model do |m|
   m.singleton_model { singleton :singleton_model }
end

but maybe there is a better way.

like image 546
Alexey Avatar asked Nov 30 '10 19:11

Alexey


3 Answers

You can use the initialize_with macro inside your factory and check to see if the object already exists, then don't create it over again. This also works when said factory is referenced by associations:

FactoryGirl.define do
  factory :league, :aliases => [:euro_cup] do
    id 1
    name "European Championship"
    owner "UEFA"
    initialize_with { League.find_or_create_by_id(id)}
  end
end

There is a similar question here with more alternatives: Using factory_girl in Rails with associations that have unique constraints. Getting duplicate errors

like image 145
CubaLibre Avatar answered Nov 05 '22 22:11

CubaLibre


@CubaLibre answer with version 5 of FactoryBot:

FactoryGirl.define do
  factory :league do
    initialize_with { League.find_or_initialize_by(id: id) }
    sequence(:id)
    name "European Championship"
  end
end
like image 2
cyrilchampier Avatar answered Nov 05 '22 23:11

cyrilchampier


Not sure if this could be useful to you.

With this setup you can create n products using the factory 'singleton_product'. All those products will have same platform (i.e. platform 'FooBar').

factory :platform do
  name 'Test Platform'
end

factory :product do
  name 'Test Product'
  platform

  trait :singleton do
    platform{
      search = Platform.find_by_name('FooBar')
      if search.blank?
        FactoryGirl.create(:platform, :name => 'FooBar')
      else
        search
      end
    }
  end

  factory :singleton_product, :traits => [:singleton]
end

You can still use the standard product factory 'product' to create a product with platform 'Test Platform', but it will fail when you call it to create the 2nd product (if platform name is set to be unique).

like image 1
Jonas Bang Christensen Avatar answered Nov 05 '22 23:11

Jonas Bang Christensen