Jump to content

Factory Bot (Rails Testing)

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Averell23 (talk | contribs) at 09:34, 24 February 2018 (Rewrote lede, removed some cruft. See talk). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Factory Bot, originally known as Factory Girl, is a software library for the Ruby programming language that provides factory methods to create test fixtures for automated software testing. The fixture objects can be created on the fly; the may be plain Ruby objects with a predefined state, ORM objects with existing database records or mock objects.

Factory Bot is often used in testing Ruby on Rails applications; where it replaces Rails' built-in fixture mechanism. Rails' default setup uses a pre-populated database as test fixtures, which are global for the complete test suite. Factory Bot, on the other hand, allows developers to define a different setup for each test and thus helps to avoid dependencies within the test suite[1].


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

 FactoryBot.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 FactoryBot.lint once before running the test suite.[2] This will build all factories and call #valid? On the factories. If any factory returns False for the valid call, Factory Bot returns FactoryBot::InvalidFactoryError along with a list of factories that failed to load.

By default all factories can be linted as follows:

FactoryBot.lint

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

 factories_lint = FactoryBot.factories.reject do |factory|
 factory.name =~ /my_factory_/
 FactoryBot.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 Bot. Before asking for a model from Factory Bot, 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[2]

Traits

Traits allow grouping of attributes which can be applied to any factory.[2][3]

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 Bot allows creating aliases for existing factories so that the factories can be reused.[2]

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 Bot allows creating unique values for a test attribute in a given format.[2][4]

 FactoryBot.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 Bot allows custom code to be injected at four different stages:[2]

after(:build)
Code can be injected after the factory is built
before(:create)
Code can be injected before the factory is saved
after(:create)
Code can be injected after the factory is saved
after(:stub)
Code can be injected before the factory is stubbed

See also

Other Testing Approaches

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

References

  1. ^ "Rails Testing".
  2. ^ a b c d e f g h "Ruby Docs - Factory Bot".
  3. ^ "Traits".
  4. ^ "Sequences".
  5. ^ "NullDB".
  6. ^ "Fixture Builder".
  7. ^ "Shoulda".
  8. ^ "Rpsec".
  9. ^ "Cappybara".