Jump to content

Factory Bot (Rails Testing)

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Dsonawa (talk | contribs) at 20:15, 13 February 2016. 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 straightforward definition syntax, support for 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 And Need For Testing

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.

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.[3]

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. 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

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]

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.

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. [5]

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

Inheritance

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 :

  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.[6]
Fixture Builder, a tool that compiles Ruby factories into fixtures before a test run.[7]
Shoulda, an extension to test/unit with additional helpers, macros, and assertions.[8]
Rspec, a behavior-driven development framework[9]
Capybara, Acceptance test framework for web applications.[10]

See also

  1. JUnit
  2. NUnit

References

  1. ^ "Rails Testing".
  2. ^ "Installation".
  3. ^ "Ruby Docs - Factory Girl".
  4. ^ "Traits".
  5. ^ "Sequences".
  6. ^ "NullDB".
  7. ^ "Fixture Builder".
  8. ^ "Shoulda".
  9. ^ "Rpsec".
  10. ^ "Cappybara".