Jump to content

Factory Bot (Rails Testing)

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Bgwhite (talk | contribs) at 01:26, 18 February 2016 (Do general fixes and cleanup. - using AWB (11895)). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Factory Girl is a testing philosophy to test the Ruby on Rails applications which is perpendicular to Fixtures. Factory girl allows the user to quickly define prototypes for each of the models and ask for instances with properties that are important to the test at hand. Factory Girl replaces fixtures in tests. This way, the user does not have to keep the fixtures up-to-date as the data model changes. Fixtures can also tend to get unwieldy as more edge cases are added. On the other hand, Factory Girl generates data on the fly and adding and removing fields is much easier. The setup of Factory Girl is similar to Fixtures.

Description

Tests become much easier to maintain when you can request a model instance that is always current. Using Factory Girl, a model is never bound to a particular phase of the application’s development. They are dynamically loaded from the current state of application. When there are new customer attributes introduced in that latest merge, Factory Girl already sees them unlike the case with a directory of fixtures.
Factory Girl has simple definition syntax. It supports multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.[1]

Installation

Factory Girl can be installed as a standard Ruby Gem install or installation can be included in the gem file and then bundle install can be run.[2]

gem install factory_girl

Using Gemfile

#Add the following line to the Gemfile
gem 'factory_girl'
#run bundle install from the shell

Fixtures

A good testing framework goes a long way in ensuring the software quality which is delivered to the customers. In testing, oftentimes data is critical but not always organized enough. Fixtures are a way of organizing test data; they reside in the fixtures folder in the project hierarchy of a rails application. Fixture is a fancy word for sample data which allows the user to populate the database with predefined data before the tests run.[3]

Factories

Defining Factories

A factory is defined by a name and its set of attributes. The name of the factory is used to determine the class of the object. Class can also be specified explicitly.[4]

 '''FactoryGirl.define do'''
         #Determine class automatically
         '''factory''' :user '''do'''
                 name = "Captain Minion"
                 superhero false
         '''end'''
         #Specific class explicitly
         '''factory''' :superhero, class: User '''do'''
                 name = "Tony Stark"
                 superhero true
         '''end'''
 '''end'''

It is a good practice to define factories providing basic attributes necessary for each class. Factories can also be inherited.

Linting a Factory

The process of executing a program that will analyze code for potential errors is called as linting. It is a good practice to run FactoryGirl.lint once before running the test suite.[4] This will build all factories and call #valid? On the factories. If any factory returns False for the valid call, Factory girl returns FactoryGirl::InvalidFactoryError along with a list of factories that failed to load.
By default all factories can be linted as follows:

 '''FactoryGirl.lint'''

To lint only selective factories, the following template can be used :

 factories_lint = FactoryGirl.factories.reject do |factory|
 factory.name =~ /my_factory_/
 '''FactoryGirl.lint''' factories_lint

Features

Less Boilerplate Code[4]

The traditional fixture model allows the user to create a unit-test for a model and reuse it in numerous tests using references to the YAML files like :

@college = YAML::load(File.open("test/fixtures/NCSU_college.yaml", "rb").read)

But the issue with this method is that you need to create multiple copies of such YAML files for different values for the models.This issue does not arise in Factory Girl. Before asking for a model from Factory Girl, it needs to be told about how to build this model. This is specified in one or more factory files. These factory files can be saved in /test/factories.rb

Traits

Traits allow grouping of attributes which can be applied to any factory.[4][5]

 '''factory''' :status '''do''' 
   title "Seeking for Full Time jobs"
 
   '''trait''' :international '''do'''
 	international true
   '''end'''
 
   '''trait''' :resident '''do'''
 	international false
   '''end'''
 
   '''trait''' :comp_sci '''do'''
 	comp_sci true
   '''end'''
 
   '''trait''' :electrical '''do'''
 	comp_sci false
   '''end'''
 	
   '''factory''' :comp_sci_international_student,  traits: [:international, :comp_sci]
   '''factory''' :electrical_resident_student,  traits: [:resident, :electrical]
 '''end'''

Alias

Factory Girl allows creating aliases for existing factories so that the factories can be reused.[4]

 '''factory''' :user, aliases: [:student, :teacher] '''do'''
  first_name    "John"
 '''end'''
 
 '''factory''' :notice '''do'''
  teacher
  #Alias used ''teacher'' for ''user''
  title "Office Hours"
 '''end'''
 
 '''factory''' :notification '''do'''
  student
  #Alias used ''student'' for ''user'' 
  title "Lecture timings"
 '''end'''

Sequences

Factory Girl allows creating unique values for a test attribute in a given format.[4][6]

 '''FactoryGirl.define''' '''do'''
   '''factory''' :title '''do'''
     sequence(:name) {|n| "Title #{n}" }
     #Title 1, Title 2 and so on...
   '''end'''
 '''end'''

Factories can be inherited while creating a factory for a class. This allows the user to reuse common attributes from parent factories and avoid writing duplicate code for duplicate attributes. Factories can be written in a nested fashion to leverage inheritance.

 '''factory''' :user '''do'''
    name "Micheal"
 
    '''factory''' :admin '''do'''
        admin_rights true
    '''end'''
 '''end'''
 
 admin_user = create(:admin)
 admin_user.name   #Micheal
 admin_user.admin_rights   #true

Parent factories can also be specified explicitly.

factory :user '''do'''
  name "Micheal"
'''end'''
 
factory :admin, parent: :user '''do'''
  admin_user true
'''end'''

Callback

Factory Girl allows custom code to be injected at four different stages:[4]

  1. after(:build) - Code can be injected after the factory is built
  2. before(:create) - Code can be injected before the factory is saved
  3. after(:create) - Code can be injected after the factory is saved
  4. after(:stub) - Code can be injected before the factory is stubbed

Other Testing Approaches

NullDB a way to speed up testing by avoiding database use.[7]
Fixture Builder, a tool that compiles Ruby factories into fixtures before a test run.[8]
Shoulda, an extension to test/unit with additional helpers, macros, and assertions.[9]
Rspec, a behavior-driven development framework[10]
Capybara, Acceptance test framework for web applications.[11]

See also

  1. JUnit
  2. NUnit

References

  1. ^ "Rails Testing".
  2. ^ "Installation".
  3. ^ "A Guide to Testing Rails Applications — Ruby on Rails Guides". guides.rubyonrails.org. Retrieved 2016-02-13.
  4. ^ a b c d e f g h "Ruby Docs - Factory Girl".
  5. ^ "Traits".
  6. ^ "Sequences".
  7. ^ "NullDB".
  8. ^ "Fixture Builder".
  9. ^ "Shoulda".
  10. ^ "Rpsec".
  11. ^ "Cappybara".