Factory_bot: When to run `FactoryGirl.lint`

Created on 17 Apr 2015  路  4Comments  路  Source: thoughtbot/factory_bot

The README says:

Recommended usage of FactoryGirl.lint is to invoke this once before the test suite is run.

But doesn't that imply that even when running a single test, e.g. as part of TDD, every factory will be linted, causing a dramatic slowdown?

Most helpful comment

Agreed. The slowdown was brutally painful when invoked the way described here.

This is not ideal, but we ended up creating a lint_spec file that serves only to invoke FactoryGirl.lint.

# spec/lint_spec.rb

require "rails_helper"

RSpec.describe "Lint" do
  it "FactoryGirl" do
    FactoryGirl.lint
  end
end

All 4 comments

Agreed. The slowdown was brutally painful when invoked the way described here.

This is not ideal, but we ended up creating a lint_spec file that serves only to invoke FactoryGirl.lint.

# spec/lint_spec.rb

require "rails_helper"

RSpec.describe "Lint" do
  it "FactoryGirl" do
    FactoryGirl.lint
  end
end

You are correct @andyw8. We actually removed that same usage from suspenders here: https://github.com/thoughtbot/suspenders/commit/0dbbc626e5da9f6ee94e1226487b4017cd2b8099 due to the exact same issue.

I'm going to open a PR to update the documentation to recommend running that in a separate task.

I edited a bit the example rake task you give to allow linting only specific factories.

# lib/tasks/factory_girl.rake
namespace :factory_girl do
  desc 'Verify that FactoryGirl factories are valid'
  task :lint, [:path] => :environment do |t, args|
    if Rails.env.test?
      begin
        DatabaseCleaner.start
        if args.path.present?
          factories = FactoryGirl.factories.select do |factory|
            factory.name.to_s =~ /#{args.path[0]}/
          end
          FactoryGirl.lint factories
        else
          FactoryGirl.lint
        end
      ensure
        DatabaseCleaner.clean
      end
    else
      system("bundle exec rake factory_girl:lint RAILS_ENV='test'")
    end
  end
end

It is particularly useful with guard-rake to watch factories and only lint the ones changing.

# Guardfile
guard :rake, task: 'factory_girl:lint' do
  watch(%r{^spec/factories/(.+)s.rb$}) { |m| "#{m[1]}" }
end

This example assume that all inherited factories in the file contains their parent name in theirs (_e.g._ user, user_with_contacts, super_user, etc.).

Could be improved by using the @parent attribute from FactoryGirl instances I guess.

FWIW: the documentation for linting now has a similar example of a rake task.

Was this page helpful?
0 / 5 - 0 ratings