Factory Bot is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies, and support for multiple factories for the same class.
Factories
Introduction
Factory Bot is a helper library for writing factories in Ruby test suites. It was previously known as Factory Girl. For legacy versions, use FactoryGirl instead of FactoryBot.
- Factory Bot Documentation (thoughtbot.github.io)
- Getting Started Guide (github.com)
- Source Code (github.com)
Defining Factories
FactoryBot.define do
factory :user do
first_name { 'John' }
last_name { 'Doe' }
birthdate { 21.years.ago }
admin { false }
sequence(:username) { |n| "user#{n}" }
end
end
See: Defining Factories.
Additional Options
Custom Class Name
factory :user, class: 'User' do
···
end
Aliases
factory :user, aliases: [:author] do
···
end
Usage Strategies
Building an Instance
FactoryBot.build(:user)
Other Build Strategies
build(:user) # → model instance (not saved)
create(:user) # → model instance (saved to database)
attributes_for(:user) # → hash of attributes
build_stubbed(:user) # stubbed out attributes (no DB hits)
Overriding Attributes
build(:user, name: 'John')
Building Collections
create_list(:user, 3)
build_list(:user, 3)
Associations
Defining Associations
factory :post do
association :author, factory: :user
association :author, factory: [:user, :admin]
end
Implicit Association
factory :post do
author # assumes there is a factory named :author
end
After-Create Hooks
factory :post do
after :create do |post|
create :theme, post: post # has_one
create_list :comment, 3, post: post # has_many
end
end
Advanced Features
Traits
factory :user do
trait :admin do
admin { true }
end
end
create :user, :admin
Traits allow you to group related attributes and behaviors together. See: Traits.
Nested Factories
factory :user do
first_name { 'John' }
factory :sample_user do
first_name { FFaker::Name.first_name }
end
end
create :sample_user
See: Inheritance.
Sub-factories
factory :user do
···
end
factory :sample_user, parent: :user do
first_name { FFaker::Name.first_name }
end
create :sample_user
Sub-factories work similarly to nested factories using the parent option.
Transient Attributes
factory :user do
transient do
upcased { true }
end
after :create do |user, options|
user.name.upcase! if options.upcased
end
end
create(:user, upcased: true)
Transient attributes are not assigned directly to model fields, but are accessible inside callbacks and hooks. See: Transient Attributes.
Standard File Locations
test/factories.rbspec/factories.rbtest/factories/*.rbspec/factories/*.rb
Place your factory definition files in any of these paths for automatic loading.