title: How can I get Factory Girl to NEVER hit the database if I am calling Factory.build in order to make my controller tests FAST?
body: <p>I am on a quest to make my Rails tests faster. I only have 520 tests, but they take 62 seconds to run in bash, and 82 seconds to run in Rubymine.</p>
  
  <p>As an example of a typical controller test, I was using this code to sign_in as a @user and create the basic @comment in a CommentsController for my RSpec controller tests:</p>
  
  <pre><code>before(:each) do
    @user = Factory.create(:user)
    sign_in @user
  
    @comment = Factory.create(:comment)
  end
  </code></pre>
  
  <p>As you might realize... this is slow. It builds a <code>@user</code>, but also builds the associations for that user. Same for the <code>@comment</code>.</p>
  
  <p>So I thought calling <code>Factory.build(:user)</code> would solve it... but I get weird errors. For example, <code>current_user</code> returns <code>nil</code>.</p>
  
  <p>So... I decided to use <code>Factory.build()</code> and stub out all the before filters in my parent controller. However, my rspec log still says a TON of inserts are hitting the database when I inspect the RSPec log afterwards (we are talking hundreds of lines of code for just 3 tests!)</p>
  
  <pre><code>  before(:each) do
      @user = Factory.build(:user)
      #sign_in @user
  
      controller.stub(:authenticate_user!) #before_filter
      controller.stub(:add_secure_model_data) #before_filter
      controller.stub(:current_user).and_return(@user)
  
      @comment = Factory.build(:comment)
    end
  </code></pre>
  
  <p>The sad fact is, the above <code>before(:each)</code> block has ZERO effect on test performance. As I discovered, calling <code>Factory.build()</code> will still internally call <code>Factory.create()</code> on the child associations.</p>
  
  <p>Here is a <code>before(:each)</code> block that effectively removes the junk produced in the RSpec log. It gave me a 35-40% test performance boost</p>
  
  <pre><code>  before(:each) do
      @user = Factory.build(:user, :role =&gt; Factory.build(:role))
      #sign_in @user
  
      controller.stub(:authenticate_user!)
      controller.stub(:add_secure_model_data)
      controller.stub(:current_user).and_return(@user)
  
      # both of these are still super slow. WTF?!
      @site_update = Factory.build(:site_update, :id =&gt; 5, :author =&gt; Factory.build(:user, :role =&gt; Factory.build(:role)))
  
      @comment = Factory.build(:comment,
                               :author =&gt; Factory.build(:user, :role =&gt; Factory.build(:role)),
                               :commentable =&gt; @site_update)
    end
  </code></pre>
  
  <p>This makes the tests run faster, but it's also ugly as sin. We can't seriously write this for every test... do we? That's nuts. I'm not doing it.</p>
  
  <p>I also want to point out that any one of these <code>Factory.build()</code> lines still takes about .15 seconds even though they are NOT hitting the database! </p>
  
  <p>Running only 3 tests still results in about .3 to .35 seconds of time taken up by factory_girl PER test! I think that is totally unacceptable. If you remove the <code>Factory.build()</code> lines, the tests run in 0.00001 seconds.</p>
  
  <p>I think the jury is in: factory_girl is one really slow library. Is the only solution to not use it?</p>
  
  <p>Here is my <code>factories.rb</code>:</p>
  
  <pre><code>Factory.define :role do |f|
    f.name "Admin"
  end
  
  Factory.define :user do |f|
    f.first_name "Banoo"
    f.last_name "Smith"
    f.sequence(:email) { |n| "Banoo.Smith#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :admin do |f|
    f.first_name "Banoo"
    f.last_name "Smith"
    f.sequence(:email) { |n| "admin#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :course_provider do |f|
    f.first_name "Josh"
    f.last_name "Bolson"
    f.sequence(:email) { |n| "josh.bolson#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :director do |f|
    f.first_name "Director"
    f.last_name "Dude"
    f.sequence(:email) { |n| "director#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :instructor do |f|
    f.first_name "Instructor"
    f.last_name "Dude"
    f.sequence(:email) { |n| "instructor#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :trainee do |f|
    f.first_name "Trainee"
    f.last_name "Dude"
    f.sequence(:email) { |n| "trainee#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
  end
  
  Factory.define :private_message do |f|
    f.subject "Subject"
    f.content "content"
    f.is_deleted_by_sender false
    f.association :sender, :factory =&gt; :user
  end
  
  Factory.define :recipient do |f|
    f.is_read false
    f.is_deleted false
    f.association :receiver, :factory =&gt; :user
    f.association :private_message
  end
  
  Factory.define :course_template do |f|
    f.name "name"
    f.description "description"
    f.association :course_provider
  end
  
  Factory.define :site_update do |f|
    f.subject "Subject"
    f.intro "intro"
    f.content "content"
    f.association :author, :factory =&gt; :user
  end
  
  Factory.define :comment do |f|
    f.content "content"
    f.association :author, :factory =&gt; :user
    f.association :commentable, :factory =&gt; :site_update
  end
  
  Factory.define :country do |f|
    f.name "Liberty"
  end
  
  Factory.define :province do |f|
    f.name "Freedom"
    f.association :country
  end
  
  Factory.define :payment_plan do |f|
    f.name "name"
    f.monthly_amount 79
    f.audience "Enterprises"
    f.active_courses "500-2000"
  end
  
  Factory.define :company do |f|
    f.name "name"
    f.phone_number "455-323-2132"
    f.address "address"
    f.postal_code "N7G-5F4"
    f.association :province
    f.association :payment_plan
  end
  
  Factory.define :company_user do |f|
    f.first_name "Dan"
    f.last_name "Grayson"
    f.sequence(:email) { |n| "dan.grayson#{n}@gmail.com" }
    f.password "secretpassword"
    f.association :role
    f.association :company
  end
  
  Factory.define :course do |f|
    f.notes "notes"
    f.difficulty 100
    f.association :course_template
    f.association :instructor, :factory =&gt; :company_user
  end
  
  Factory.define :study_group do |f|
    f.name "name"
  end
  
  Factory.define :help_category do |f|
    f.name "name"
  end
  
  Factory.define :help_document do |f|
    f.question "question"
    f.content "content"
    f.association :category, :factory =&gt; :help_category
  end
  
  Factory.define :tag do |f|
    f.name "name"
  end
  
  Factory.define :partial_mapping do |f|
    f.from_suffix "ing"
    f.to_suffix "ing"
  end
  
  Factory.define :newsletter do |f|
    f.subject "subject"
    f.content "content"
  end
  
  Factory.define :press_contact do |f|
    f.full_name "Banoo Smith"
    f.email 'Banoo.Smith@gmail.com'
    f.phone_number "455-323-2132"
    f.address "address"
    f.postal_code "N9B-3W5"
    f.association :province
  end
  
  Factory.define :press_release do |f|
    f.headline "Headline"
    f.origin "origin"
    f.intro "intro"
    f.body "body"
    f.association :contact, :factory =&gt; :press_contact
  end
  
  Factory.define :theme do |f|
  
  end
  </code></pre>
  
  <p>And interesting benchmark. It takes .1 to .14 seconds on average to make a call to <code>Factory.create(:user)</code>:</p>
  
  <pre><code>$ rails runner 'Benchmark.bm {|x| x.report { 100.times { Factory.create(:user) } } }' 
        user     system      total        real
    9.940000   0.080000  10.020000 ( 14.872736)
  </code></pre>
  
  <p>Even a <code>Factory.build(:user)</code> takes forever... and this is with <code>:default_strategy =&gt; :build</code> turned on!</p>
  
  <pre><code>$ rails runner 'Benchmark.bm {|x| x.report { 100.times { Factory.build(:user) } } }'
        user     system      total        real
    9.350000   0.030000   9.380000 ( 11.798339)
  </code></pre>
  
  <p>Clearly this is evidence that something is wrong with factory_girl. The solution is to get rid of it or make sure it's using <code>Factory.build</code>. That is the answer.</p>
  
  <p>Since I have basically solved my own problem, I am wondering why Factory_girl is so popular, and why is it "common wisdom"? One can objectively conclude that whatever benefits may be gained by using Factory Girl - and there's a lot of nice things about it - it is not worth the performance cost. I am sure a better factory gem could be developed that is much more performant... but factory_girl is unfortunately and regretfully not it.</p>
  
  <p>My solution below uses basic object instantiation and stubs, and the tests continue to pass. I think using basic Ruby, stubs and filling in the object values manually on a per-test basis is the 'right' thing to do if you want to avoid fixtures and also get high performance when running tests.</p>