Claude Skills Guide

Claude Code Factory Bot Test Data Guide

Factory Bot is a Ruby library for building test data fixtures in a flexible and maintainable way. When combined with Claude Code, you can automate factory creation, generate complex test scenarios, and build robust test suites faster than ever.

Understanding Factory Bot Basics

Factory Bot replaces traditional Rails fixtures with a more expressive, configurable approach to test data. Instead of static YAML files, you define factories as Ruby classes that can generate objects with default values, associations, and dynamic attributes.

Setting Up Factory Bot in Your Project

First, add Factory Bot to your Gemfile:

group :test do
  gem 'factory_bot_rails'
end

Then run bundle install and configure Factory Bot in your test setup:

# spec/rails_helper.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

Defining Your First Factory

Create factories in spec/factories/ with a clear, consistent naming convention:

# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@example.com" }
    first_name { "John" }
    last_name { "Doe" }
    password { "securePassword123" }
    admin { false }

    factory :admin_user do
      admin { true }
      role { "admin" }
    end
  end
end

Using Factory Bot with Claude Code

When working with Claude Code, you can use its understanding of Factory Bot to generate factories for your existing models and create sophisticated test data scenarios.

Generating Factories from Models

Ask Claude Code to analyze your models and create appropriate factories:

Create Factory Bot factories for my User, Post, and Comment models. 
Include associations, valid sequences, and trait variations for common states.

Claude Code will generate factories similar to:

# spec/factories/posts.rb
FactoryBot.define do
  factory :post do
    title { "Sample Post Title" }
    body { "This is the post content body." }
    published { false }
    association :author, factory: :user

    trait :published do
      published { true }
      published_at { Time.current }
    end

    trait :draft do
      published { false }
    end

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

# spec/factories/comments.rb
FactoryBot.define do
  factory :comment do
    body { "Great article!" }
    association :post
    association :author, factory: :user
  end
end

Building Complex Test Scenarios

Factory Bot shines when you need to create related records for testing complex associations:

# Creating a post with multiple comments
let(:post_with_comments) do
  create(:post, :published).tap do |post|
    create_list(:comment, 3, post: post)
  end
end

# Creating a user with posts
let(:prolific_author) do
  create(:user, first_name: "Prolific").tap do |user|
    create_list(:post, 10, :published, author: user)
  end
end

Advanced Factory Bot Patterns

Using Transient Attributes

Transient attributes don’t map directly to model fields but customize factory behavior:

FactoryBot.define do
  factory :order do
    transient do
      item_count { 3 }
      include_discount { false }
    end

    after(:build) do |order, evaluator|
      if evaluator.include_discount
        order.discount_percentage = 15
      end
    end

    after(:create) do |order, evaluator|
      create_list(:line_item, evaluator.item_count, order: order)
    end
  end
end

Factory Sequences for Unique Data

Ensure unique values across test runs with sequences:

FactoryBot.define do
  factory :account do
    sequence(:subdomain) { |n| "company#{n}" }
    sequence(:email) { |n| "admin#{n}@company.com" }
    name { "Company Name" }
  end
end

Inheritance and Aliases

Create base factories and extend them:

FactoryBot.define do
  factory :post do
    title { "Default Title" }
    body { "Default body content" }
    author

    factory :article do
      type { "Article" }
      category { "tech" }
    end

    factory :announcement do
      type { "Announcement" }
      priority { "high" }
    end
  end

  factory :guest_post, parent: :post do
    author { create(:user, :guest) }
  end
end

Integration with RSpec

Factory Bot Methods in Tests

After configuring the syntax methods, use factories directly in your tests:

RSpec.describe Post do
  describe "#publish!" do
    it "changes published status to true" do
      post = create(:post, :draft)
      post.publish!
      expect(post.published?).to be true
    end

    it "sets published_at timestamp" do
      post = create(:post, :draft)
      expect { post.publish! }.to change(post, :published_at).from(nil)
    end

    it "notifies followers" do
      post = create(:post)
      follower = create(:user, :following, post: post)
      expect { post.publish! }.to change { follower.notifications.count }.by(1)
    end
  end
end

Using Factory Traits for Test Variations

Organize test data variations with traits:

RSpec.describe User do
  describe "#can_post?" do
    context "with active subscription" do
      let(:user) { create(:user, :active, subscription: "pro") }
      it { expect(user.can_post?).to be true }
    end

    context "with basic subscription" do
      let(:user) { create(:user, :active, subscription: "basic") }
      it { expect(user.can_post?).to be false }
    end

    context "with inactive account" do
      let(:user) { create(:user, :inactive) }
      it { expect(user.can_post?).to be false }
    end
  end
end

# Factory with traits
FactoryBot.define do
  factory :user do
    name { "Test User" }
    subscription { "free" }

    trait :active do
      active { true }
    end

    trait :inactive do
      active { false }
    end
  end
end

Best Practices for Factory Bot

Keep Factories Fast

Avoid slow operations in factories:

# Bad - file processing in factory
factory :document do
  file { File.open(Rails.root.join("spec/fixtures/large.pdf")) }
end

# Good - minimal, fast factory
factory :document do
  filename { "document.pdf" }
  content_type { "application/pdf" }
end

Use build_stubbed for Unit Tests

For tests that don’t hit the database, use stubbed objects:

# Much faster - no database write
user = build_stubbed(:user)
expect(user.name).to eq("John Doe")

Clean Up Between Tests

Factory Bot handles cleanup automatically, but for performance-critical tests:

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    FactoryBot.lint
  end
end

Working with Associations

Handling Dependent Records

FactoryBot.define do
  factory :project do
    name { "My Project" }
    owner

    # Automatically create owner if not provided
    association :owner, factory: :user

    # With nested attributes
    factory :project_with_tasks do
      after(:create) do |project|
        create_list(:task, 5, project: project)
      end
    end
  end
end

Self-Referential Associations

FactoryBot.define do
  factory :user do
    sequence(:username) { |n| "user#{n}" }
    
    factory :user_with_friends do
      after(:create) do |user|
        friend1 = create(:user)
        friend2 = create(:user)
        user.friendships.create!(friend: friend1)
        user.friendships.create!(friend: friend2)
      end
    end
  end
end

Conclusion

Factory Bot combined with Claude Code creates a powerful testing workflow. Use Claude Code to generate factories from your models, create test data scenarios, and maintain clean, reusable factory definitions. This approach ensures your test suite remains fast, maintainable, and expressive.

Built by theluckystrike — More at zovo.one