Never Fear, Traits are Here

I can’t count the number of times I’ve worked on Rails apps where I’m using Factory Girl and want to declare a factory with multiple parents. We’ve all been there, don’t lie.

FactoryGirl.define do
  factory :user do
    name "Friendly User"

    factory :admin do
      admin true
    end

    factory :male_user do
      gender "Male"
      name   "John Doe"

      factory :male_admin_user do
        admin true
      end

      factory :teenage_male_user do
        date_of_birth { 15.years.ago }

        factory :teenage_admin_male_user do
          admin true
        end
      end
    end

    factory :female_user do
      gender "Female"
      name   "Jane Doe"

      factory :female_admin_user do
        admin true
      end

      factory :teenage_female_user do
        date_of_birth { 15.years.ago }

        factory :teenage_admin_female_user do
          admin true
        end
      end
    end
  end
end

Oh, the duplication! This isn’t DRY.

Factory Girl 2.0.4 introduces traits. I’ll cut to the chase:

FactoryGirl.define do
  factory :user do
    name "Friendly User"

    trait :admin do
      admin true
    end

    trait :male do
      gender "Male"
      name   "John Doe"
    end

    trait :female do
      gender "Female"
      name   "Jane Doe"
    end

    trait :teenager do
      date_of_birth { 15.years.ago }
    end

    factory :male_user,                 :traits => [:male]
    factory :female_user,               :traits => [:female]
    factory :teenage_male_user,         :traits => [:teenager, :male]
    factory :teenage_female_user,       :traits => [:teenager, :female]
    factory :male_admin_user,           :traits => [:admin, :male]
    factory :female_admin_user,         :traits => [:admin, :female]
    factory :teenage_admin_male_user,   :traits => [:teenager, :admin, :male]
    factory :teenage_admin_female_user, :traits => [:teenager, :admin, :female]
  end
end

Mix and match however you please. Bonus: you can assign traits like plain-old attributes.

FactoryGirl.define do
  factory :user do
    name "Friendly User"

    trait :admin do
      admin true
    end

    trait :male do
      gender "Male"
      name   "John Doe"
    end

    factory :male_admin_user do
      male
      admin
    end
  end
end

Many props go out to Thomas Walpole, who helped get a lot of this written; thanks Thomas!

So go ahead, get your trait on; you’ll thank me later.

Sharpen your programming skills by completing coding exercises that are reviewed by other developers at Upcase today.