FactoryBot 1.2: Adding Excitement to Stale Factories

Joe Ferris

Some like it hot

''

The FactoryBot syntax was designed to balance best practices, consistency, readability, and brevity, and to handle all of the features we wanted to support. However, users haven’t been shy to point out that not everybody is a fan of our factory flavor

If you think mixing in some FactoryBot would be good for your project, but don’t care much for the taste, you can try out one of the new alternate syntaxes:

# Use factory_bot machinist-style
require 'factory_bot/syntax/blueprint'
require 'factory_bot/syntax/sham'
require 'factory_bot/syntax/make'

Sham.email {|n| "email#{n}@example.com" }

User.blueprint do
  name  { 'Billy Bob' }
  email { Sham.email  }
end

Or build factories like daddy did

require 'factory_bot/syntax/generate'

User.generate
User.generate!
User.spawn
User.generate {|user| user.something }

Give one of our other flavors a whirl, and let us know what you think.

Mix in a few stubs to cut down on fat

If you do view testing, or isolation testing in general, you’re probably sick of creating database records that you’re just going to return from a stubbed method anyway. Want pure mock objects? Don’t want to stub out attributes you need for view tests? Use Factory.stub:

context "on GET to show" do
  setup do
    @user = Factory.stub(:user)
    stub(User).find(anything) { @user }
  end

  should "display the user's name" do
    # ...
  end

  # ... more view tests
end

Just a spoonful of sugar

Sometimes a sequence is required for just a single factory, and defining the sequence separately is just a little too much to type. Got a one-off sequence? Define it inline:

Factory.define :airport do |factory|
  factory.sequence(:code) {|n| "AA#{n}" }
end

Don’t use a fork when a spoon will do

factory_bot works great for any class that accepts attributes after initialization, like ActiveMerchant CreditCards. However, doing a Factory.build to avoid a save! for other classes can make these factories a little harder to swallow. If you’re using factory_bot for a class that doesn’t use save!, try changing the default strategy:

Factory.define :credit_card,
    :class            => 'ActiveMerchant::Billing::CreditCard',
    :default_strategy => :build do |factory|
  # ...attributes for a credit card...
end

I eat my factories dry

Defining attributes you don’t need on a factory can cause your tests to make assumptions they shouldn’t, but it can be pretty inconvenient to repeat all those base attributes for convenient alternate factories. Falling asleep from typing the same attributes over and over? Wake up to the most-requested feature for factory_bot: inheritence!

Factory.define :post do |factory|
  factory.title "Every post needs a title!"
end

Factory.define :approved_post, :parent => :post do |factory|
  factory.approved true
  # Approved posts need to be approved by somebody!
  factory.association :approver, :factory => :user
end

Nutritional information

The FactoryBot docs have been updated and revamped, so be sure to hit those up if you have questions on older or newer functionality.

If you’d like to add another syntax, or have a feature you’re itching for, please create a clone of our repository on github (please be sure to read the contribution guidelines).

Thanks to Josh Nichols for documentation patches, and a big thank you to Eugene Bolshakov for his huge contributions to this release.


Disclaimer:

Looking for FactoryGirl? The library was renamed in 2017. Project name history can be found here.

Visit our Open Source page to learn more about our team’s contributions.