in ruby rubyonrails factory_girl rspec testing fixtures ~ read.

Factory Girl Rails

Fixtures are for producing test data, for a test data has to be generated and using that data assertions have to be made. The main problem with fixtures is that it is all or nothing, so for a single test we might have to load all of the fixture or all fixtures for a particular model like post, user, etc, and all this data is static data which is stored in a yml file, on the other hand factory_girl the data is dynamic and we are using ruby to create that data. With factory girl you can create default objects and also very specific objects. Anything that you don't care about in a spec you can largely ignore and let the factory girl defaults take care of that and also at the same time anything that is important to the given spec is stated in the call to factory girl.
factory_girl is meant to replace fixtures.

FactoryGirl.define do  
  factory :user do
    name 'John'
    email { "{name}@mail.com" }
    last_signed_in { 10.days.ago }
    password 'password'
    github_username { "#{name}-github" }
  end
end

require 'factory_girl'  
require './factories'

include FactoryGirl::Syntax::Methods

build(:user, name: 'James')  
attributes_for(:user, name: 'James')  
attributes_for_pair(:user, name: 'James')  
build_stubbed(:user)  

We can define a sequence for generating users with different emails, this is helpful when email attribute is unique.

FactoryGirl.define do  
  factory :user do
    name 'User'
    sequence(:email) { |i| "#{name}_#{i}@example.com"}
    password 'password'
    last_sign_in_at { 10.days.ago }
    github_username { "#{name}_github" }
  end
end  

Also care should be taken when using a dependent attribute like
sequence(:email) { |i| "#{name}_#{i}@example.com" } then the whole thing should be wrapped in curly braces so that it gets lazily evaluated. If not then it will raise such an error
ArgumentError: Trait not registered: name

attributes_for This will give us a nice hash of attributes which can be used in controller specs.

attributes_for(:user)  
=> {:email=>"Saad_2@example.com", :password=>"password", :last_sign_in_at=>Fri, 24 Jun 2016 13:14:30 UTC +00:00, :github_username=>"Saad_github", :name=>"Saad"}

There is also _pair and _list variant, and pair will give us a list of 2 user data.

attributes_for_pair(:user)  
[{:email=>"Saad_4@example.com", :password=>"password", :last_sign_in_at=>Fri, 24 Jun 2016 13:22:54 UTC +00:00, :github_username=>"Saad_github", :name=>"Saad"},
 {:email=>"Saad_5@example.com", :password=>"password", :last_sign_in_at=>Fri, 24 Jun 2016 13:22:54 UTC +00:00, :github_username=>"Saad_github", :name=>"Saad"}]

Similarly attributes_for_list(:user, 4) will accept another argument to give us the number of list items.

build_stubbed

the difference between build and build_stubbed is that even though there is no database build_stubbed will create objects that will act as if it were a persisted object, also if the object has associations then those associations will also be created. While using build only will not create objects that acts as persisted.

note: When object has associations then create method will create those associations, build will also create those associations. So to insulate ourselves from database it is advised to use build_stubbed, will follow the associations and will build_stubbed on associations as well.

traits are used to override behaviour or add additional behaviour.

  factory :user do
    sequence(:email) { |i| "#{name}_#{i}@example.com"}
    password 'password'
    last_sign_in_at { 10.days.ago }
    github_username { "#{name}_github" }
    name 'Saad'

    trait :admin do
      name 'Admin'
    end
  end

now using this what we can do is build_stubbed(:user, :admin)

Another good use of factory_girl is to define seed data.