What it is
FactoryBot builds test objects from declarative factories, replacing static fixtures with composable, overridable definitions.
Define factories with defaults, then build or create instances, overriding only what a test cares about. Traits and associations compose.
Installation
gem 'factory_bot_rails', group: %i[development test]Getting started
The smallest useful thing you can do with it, and what each part means.
ruby
FactoryBot.define do
factory :book do
sequence(:title) { |n| "Book #{n}" } # unique per instance
year { 1990 }
association :author
trait :classic do
year { 1950 }
end
trait :with_reviews do
# after(:create) because reviews need a persisted book.
after(:create) { |book| create_list(:review, 3, book: book) }
end
factory :classic_book, traits: [:classic]
end
end
build(:book) # in memory, not saved
create(:book, title: 'Dune') # persisted
create(:book, :classic, :with_reviews)
create_list(:book, 5, year: 2020)Advanced usage
Where the library earns its place over a simpler alternative.
ruby
# build_stubbed does not touch the database at all — much faster
# when persistence is irrelevant to the test.
let(:book) { build_stubbed(:book) }
# Lint every factory in CI so a schema change cannot silently break them.
RSpec.describe 'factories' do
it 'are all valid' do
expect { FactoryBot.lint(traits: true) }.not_to raise_error
end
end
# Avoid creating associations that the test does not need.
factory :book do
association :author, strategy: :build # not persisted unless required
endErrors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Validation failed: title has already been taken
- A static default on a unique column. Use a sequence.
- Tests are slow
- Factories are creating deep association trees. Use build_stubbed, or strategy: :build on associations.
Best practices
- Use build_stubbed when the test does not need the database — it is dramatically faster.
- Keep factories minimal and valid; add extras through traits rather than defaults.
- Run FactoryBot.lint in CI so schema drift is caught immediately.
- Use sequences for unique columns to avoid uniqueness collisions between examples.
Background
Why it exists, and what it was reacting to.
Fixtures are global, order-dependent and drift from the schema. FactoryBot lets each test build exactly the object it needs, stating only the attributes relevant to that test.
