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:56, 24 February 2018 (Defining Factories: rm unnecessary link to ruby docs). 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[1], 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[2][3].


Factories

Defining Factories

A factory is defined by a name and its set of attributes. The class of the test object can is either determined through the name of the factory or set explicitly.[4]

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

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

 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:[4]

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.[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]
  • xUnit: JUnit, NUnit, etc.

References

  1. ^ "Project Naming History". {{cite web}}: Missing or empty |url= (help); Text "https://github.com/thoughtbot/factory_bot/blob/master/NAME.md" ignored (help)
  2. ^ "Waiting For a FactoryGirl". {{cite web}}: Missing or empty |url= (help); Text "https://robots.thoughtbot.com/waiting-for-a-factory-girl" ignored (help)
  3. ^ "Rails Testing".
  4. ^ a b c d e f g "Ruby Docs - Factory Bot".
  5. ^ "Traits".
  6. ^ "Sequences".
  7. ^ "NullDB".
  8. ^ "Fixture Builder".
  9. ^ "Shoulda".
  10. ^ "Rpsec".
  11. ^ "Cappybara".