Factory Bot (Rails Testing)
![]() | This article may be confusing or unclear to readers. (March 2016) |
![]() | This article contains instructions, advice, or how-to content. (May 2017) |
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
- ^ "Rails Testing".
- ^ a b c d e f g h "Ruby Docs - Factory Bot".
- ^ "Traits".
- ^ "Sequences".
- ^ "NullDB".
- ^ "Fixture Builder".
- ^ "Shoulda".
- ^ "Rpsec".
- ^ "Cappybara".