Back to Repositories

Testing FactoryBot Attribute Overrides with User Permissions in factory_bot

This test suite validates attribute override functionality in FactoryBot, specifically focusing on user permissions and secure post creation. It tests the interaction between user admin status and the ability to set secure attributes on posts.

Test Coverage Overview

The test suite comprehensively covers attribute override scenarios in a User-Post relationship model.

  • Tests admin user post creation with secure attributes
  • Validates non-admin user post creation restrictions
  • Verifies default behavior for posts without user association
  • Examines secure attribute assignment permissions

Implementation Analysis

The implementation uses RSpec’s context-based testing approach with FactoryBot factories.

Key patterns include:
  • Factory definition with nested admin factory
  • Dynamic attribute assignment using blocks
  • Conditional attribute setting based on user permissions
  • Use of let blocks for test data preparation

Technical Details

Testing infrastructure includes:
  • RSpec as the testing framework
  • FactoryBot for test data generation
  • Custom model definitions with relationships
  • Boolean flag handling for admin status
  • Active Record associations between User and Post models

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Ruby.

  • Clear context separation for different test scenarios
  • DRY principle through shared attribute hashes
  • Proper setup isolation using before blocks
  • Descriptive context naming for better readability
  • Effective use of subject blocks for test focus

thoughtbot/factory_bot

spec/acceptance/overrides_spec.rb

            
describe "attribute overrides" do
  before do
    define_model("User", admin: :boolean)
    define_model("Post", title: :string,
      secure: :boolean,
      user_id: :integer) do
      belongs_to :user

      def secure=(value)
        return unless user&.admin?

        write_attribute(:secure, value)
      end
    end

    FactoryBot.define do
      factory :user do
        factory :admin do
          admin { true }
        end
      end

      factory :post do
        user
        title { "default title" }
      end
    end
  end

  let(:admin) { FactoryBot.create(:admin) }

  let(:post_attributes) do
    {secure: false}
  end

  let(:non_admin_post_attributes) do
    post_attributes[:user] = FactoryBot.create(:user)
    post_attributes
  end

  let(:admin_post_attributes) do
    post_attributes[:user] = admin
    post_attributes
  end

  context "with an admin posting" do
    subject { FactoryBot.create(:post, admin_post_attributes) }
    its(:secure) { should eq false }
  end

  context "with a non-admin posting" do
    subject { FactoryBot.create(:post, non_admin_post_attributes) }
    its(:secure) { should be_nil }
  end

  context "with no user posting" do
    subject { FactoryBot.create(:post, post_attributes) }
    its(:secure) { should be_nil }
  end
end