Back to Repositories

Testing Association Attribute Behavior in factory_bot

This test suite evaluates the Association attribute functionality in FactoryBot, focusing on association creation and handling. It verifies proper association building, name handling, and override application within factory definitions.

Test Coverage Overview

The test suite provides comprehensive coverage of FactoryBot’s Association attribute implementation.

Key areas tested include:
  • Association attribute instantiation and properties
  • Association building via proc execution
  • String-to-symbol name conversion
  • Override parameter handling

Implementation Analysis

The testing approach uses RSpec’s describe blocks to organize distinct test scenarios for the Association class. It leverages RSpec’s let statements for setup and employs doubles for isolation testing.

Notable patterns include:
  • Method stubbing with allow/receive
  • Subject-based testing with RSpec its blocks
  • Module extension for method definition

Technical Details

Testing tools and setup:
  • RSpec as the testing framework
  • Test doubles for association mocking
  • Dynamic module creation for method definition
  • Before blocks for test preparation
  • Subject helper for DRY testing

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Ruby.

Notable practices include:
  • Isolation of test subjects using doubles
  • Descriptive context naming
  • DRY setup using let statements
  • Focused test cases with single assertions
  • Clear separation of setup and expectations

thoughtbot/factory_bot

spec/factory_bot/attribute/association_spec.rb

            
describe FactoryBot::Attribute::Association do
  let(:name) { :author }
  let(:factory) { :user }
  let(:overrides) { {first_name: "John"} }
  let(:association) { double("association") }

  subject { FactoryBot::Attribute::Association.new(name, factory, overrides) }

  before do
    # Define an '#association' instance method allowing it to be mocked.
    # Usually this is determined via '#method_missing'
    missing_methods = Module.new {
      def association(*args)
      end
    }
    subject.extend(missing_methods)

    allow(subject)
      .to receive(:association).with(any_args).and_return association
  end

  it { should be_association }
  its(:name) { should eq name }

  it "builds the association when calling the proc" do
    expect(subject.to_proc.call).to eq association
  end

  it "builds the association when calling the proc" do
    subject.to_proc.call
    expect(subject).to have_received(:association).with(factory, overrides)
  end
end

describe FactoryBot::Attribute::Association, "with a string name" do
  subject { FactoryBot::Attribute::Association.new("name", :user, {}) }
  its(:name) { should eq :name }
end