Factory Bot Integration

FakeDataDSL integrates seamlessly with Factory Bot to provide powerful test data generation with the simplicity of Factory Bot's DSL.

Quick Start

1. Define a Factory

# spec/factories.rb or spec/support/fake_data_factories.rb
require 'fake_data_dsl'

FakeDataDSL.define_factory(:user, schema: "User") do
  trait(:admin) do
    role { "admin" }
  end

  trait(:inactive) do
    active { false }
  end

  trait(:with_address) do
    address { FakeDataDSL.generate("Address") }
  end
end

2. Use in Tests

# spec/models/user_spec.rb
RSpec.describe User do
  it "creates a valid user" do
    user = create(:user)
    expect(user).to be_valid
  end

  it "creates an admin user" do
    admin = create(:user, :admin)
    expect(admin.role).to eq("admin")
  end

  it "accepts field overrides" do
    user = create(:user, name: "Custom Name", email: "custom@example.com")
    expect(user.name).to eq("Custom Name")
  end
end

RSpec Helpers

Setup

# spec/spec_helper.rb
require 'fake_data_dsl'
require 'fake_data_dsl/factory_bot_integration'

RSpec.configure do |config|
  config.include FakeDataDSL::FactoryBotIntegration::RSpec
end

Available Helpers

# Build data without creating records
user_data = fake_data_build(:user)
user_data = build_fake_data(:user)  # Alias

# With traits
admin_data = fake_data_build(:user, :admin)

# With overrides
custom_data = fake_data_build(:user, :admin, name: "Jane Doe")

Defining Factories

Basic Factory

FakeDataDSL.define_factory(:user, schema: "User")

Factory with Traits

FakeDataDSL.define_factory(:user, schema: "User") do
  trait(:admin) do
    role { "admin" }
    permissions { ["read", "write", "delete"] }
  end

  trait(:guest) do
    role { "guest" }
    permissions { ["read"] }
  end

  trait(:verified) do
    email_verified { true }
    phone_verified { true }
  end
end

Combining Traits

# Traits can be combined
create(:user, :admin, :verified)
create(:user, :guest, name: "Anonymous")

Schema Requirements

Your DSL schemas should be loaded before defining factories:

# Load schemas first
FakeDataDSL.load_schemas("schemas/")

# Then define factories
FakeDataDSL.define_factory(:user, schema: "User")
FakeDataDSL.define_factory(:order, schema: "Order")

Example Schema

# schemas/user.dsl
User:
  id: uuid
  name: name
  email: email
  role: enum(user, admin, moderator)
  active: boolean(true:90%)
  created_at: timestamp

Advanced Usage

Custom Factory Logic

FakeDataDSL.define_factory(:user, schema: "User") do
  trait(:with_orders) do
    orders { 
      3.times.map { FakeDataDSL::FactoryBotIntegration.build(:order) }
    }
  end
end

Sequence Support

FakeDataDSL.define_factory(:user, schema: "User") do
  trait(:numbered) do
    # Use schema's built-in sequence type
    # or override with custom sequence
    id { |n| "user_#{n}" }
  end
end

Dependent Attributes

FakeDataDSL.define_factory(:user, schema: "User") do
  trait(:consistent_name) do
    first_name { "John" }
    last_name { "Doe" }
    email { "john.doe@example.com" }
  end
end

Integration with Factory Bot (Optional)

If Factory Bot is already installed, factories are automatically registered:

# This just works if Factory Bot is available
FactoryBot.create(:user)
FactoryBot.create(:user, :admin)
FactoryBot.build_list(:user, 10)

Best Practices

1. Organize Factories by Domain

# spec/support/factories/users.rb
FakeDataDSL.define_factory(:user, schema: "User") { ... }
FakeDataDSL.define_factory(:admin_user, schema: "AdminUser") { ... }

# spec/support/factories/orders.rb
FakeDataDSL.define_factory(:order, schema: "Order") { ... }
FakeDataDSL.define_factory(:order_item, schema: "OrderItem") { ... }

2. Use Traits for Common Scenarios

FakeDataDSL.define_factory(:user, schema: "User") do
  # State traits
  trait(:active) { active { true } }
  trait(:inactive) { active { false } }

  # Role traits
  trait(:admin) { role { "admin" } }
  trait(:guest) { role { "guest" } }

  # Feature traits
  trait(:with_2fa) { two_factor_enabled { true } }
  trait(:premium) { subscription_tier { "premium" } }
end

3. Keep Factories DRY

# Base user factory
FakeDataDSL.define_factory(:user, schema: "User")

# Specialized factories inherit behavior
FakeDataDSL.define_factory(:admin, schema: "AdminUser") do
  trait(:super_admin) { permissions { ["all"] } }
end

Troubleshooting

Factory Not Found

# Error: Unknown factory: :user

# Solution: Ensure factory is defined before use
FakeDataDSL.define_factory(:user, schema: "User")

Schema Not Found

# Error: Unknown schema: User

# Solution: Load schemas before defining factories
FakeDataDSL.load_schemas("schemas/")
FakeDataDSL.define_factory(:user, schema: "User")

Trait Overrides Not Working

# Traits should return hashes or use block syntax
trait(:admin) do
  role { "admin" }  # Correct: block syntax
end

# Not: role: "admin"  # This won't work as expected

See Also