Factory Bot for flexible test data generation

Sarah Mitchell Feb 2026
1 tab
# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@example.com" }
    name { Faker::Name.name }
    password { 'password123' }

    trait :admin do
      role { 'admin' }
    end

    trait :with_posts do
      transient do
        posts_count { 3 }
      end

      after(:create) do |user, evaluator|
        create_list(:post, evaluator.posts_count, user: user)
      end
    end

    trait :inactive do
      status { 'inactive' }
      deactivated_at { 1.week.ago }
    end

    factory :admin_user, traits: [:admin]
  end

  factory :profile do
    user
    bio { Faker::Lorem.paragraph }
    avatar_url { Faker::Avatar.image }
  end
end

# spec/factories/posts.rb
FactoryBot.define do
  factory :post do
    user
    title { Faker::Book.title }
    content { Faker::Lorem.paragraphs(number: 3).join("\n") }
    status { 'draft' }

    trait :published do
      status { 'published' }
      published_at { 1.day.ago }
    end

    trait :with_comments do
      after(:create) do |post|
        create_list(:comment, 3, post: post)
      end
    end

    factory :published_post, traits: [:published]
  end
end

# Using factories in tests
# Build (not saved)
user = build(:user)
user.persisted?  # => false

# Create (saved)
user = create(:user)
user.persisted?  # => true

# Build stubbed (fastest - no database)
user = build_stubbed(:user)
user.id  # => 1001 (fake ID)

# With traits
admin = create(:user, :admin)
user_with_posts = create(:user, :with_posts, posts_count: 5)

# Override attributes
user = create(:user, email: 'specific@example.com', name: 'John')

# Associations
post = create(:post)  # Automatically creates associated user
post.user.present?  # => true

# Explicit association
user = create(:user)
post = create(:post, user: user)

# Create list
users = create_list(:user, 5)
admins = create_list(:user, 3, :admin)

# Attributes for (hash without create)
attrs = attributes_for(:user)
# => { email: "...", name: "...", password: "..." }
1 file · ruby Explain with highlit

Factory Bot creates test data with minimal boilerplate. Factories define blueprints for model creation. I use traits for variations—published posts, admin users. Sequences generate unique values. Associations automatically create related records. Transient attributes pass data without persisting. Callbacks modify objects after build/create. build creates unsaved instances; create persists to database. build_stubbed creates objects bypassing database entirely—fastest for unit tests. Factories keep tests maintainable—updating schemas requires only factory changes. I prefer explicit associations over create_list for clarity. FactoryBot makes TDD enjoyable by eliminating test data drudgery.