Skip callbacks on Factory Girl and Rspec

I’m testing a model with an after create callback that I’d like to run only on some occasions while testing. How can I skip/run callbacks from a factory?

class User < ActiveRecord::Base
  after_create :run_something
  ...
end

Factory:

FactoryGirl.define do
  factory :user do
    first_name "Luiz"
    last_name "Branco"
    ...
    # skip callback

    factory :with_run_something do
      # run callback
  end
end

Rspec factory girl issue

I have an rspec/factory girl test where I can’t get a test to pass. I’m using devise where current_user calls the currently logged in User model. I can load up a test console and type in u = Factory(:

Cucumber and Rspec sharing factory girl factories

I’m designing a test around rails using Cucumber and Rspec and I was wondering if it is good practice sharing the Factory Girl factory code between the Cucumber acceptance test and Rspec unit tests. A

Factory girl and rspec unit testing

I am using factory_girl_rails and rspec and run into trouble, raises the folloing error 1) WebsiteLink when link is external Failure/Error: website_link.external should be false expected #<FalseCl

using factory girl, rspec2 and rails 3.1.0

Currently I’m trying to integrate factory girl for my testing framework. I was successfully able to integrate factory girl with my rails 3.1.0 app and its working fine. I’m using rspec2 factory gir

Using Factory Girl with Rspec

I have set up Rspec with a rails4 app however the tests are returning: Failure/Error: user = Factory(:user) NoMethodError: undefined method `Factory’ for #<RSpec::Core::ExampleGroup::Nested_4::Nest

rspec with factory girl

I have the following factories: Factory.define :producer, :class => User do |f| f.sequence(:email) { |n| producer_#{n}@shit.com } f.password foobar f.password_confirmation foobar f.role prod

Using Factory Girl with Rspec Views

So I want to test some views using Rspec and Factory Girl, but I don’t know how to assign a factory to a view properly. All of the information I see online uses stubbing, and although stubbing is fine

Testing Devise with RSpec and Factory Girl

EDIT Read my comment to this question I’m very new to rails, so please bear with me. I’ve been trying to configure a test for Devise using factory girl and rspec. This has taken me the best part of 2

rails 3 tutorial : rspec + factory_girl_rails problem

i’ve been following the Rails tutorial (http://railstutorial.org/chapters/beginning , Rails 3 version), and i’ve stopped at 11th chapter when using Factory Girl and Rspec, I have a test that isn’t pas

Non-rails application with RSpec, ActiveRecord and Factory Girl

How to properly implement RSpec, ActiveRecord and Factory Girl in non-rails application. I also need that every test case would run on a clean database. Thanks!

Answers

In my case I have the callback loading something to my redis cache. But then I did not have/want a redis instance running for my test environment.

after_create :load_to_cache

def load_to_cache
  Redis.load_to_cache
end

For my situation, similar to above, I just stubbed my load_to_cache method in my spec_helper, with:

Redis.stub(:load_to_cache)

Also, in certain situation where I want to the test this, I just have to unstub them in the before block of the corresponding Rspec test cases.

I know you might have something more complicated happening in your after_create or might not find this very elegant. You can try to cancel the callback defined in your model, by defining an after_create hook in your Factory (refer to factory_girl docs), where you can probably define a the same callback and return false, according to the ‘Canceling callbacks’ section of this article. (I am unsure about order in which callback are executed, which is why I didn’t go for this option).

Lastly, (sorry I am not able to find the article) Ruby allows you to use some dirty meta programming to unhook a callback hook (you will have to reset it). I guess this would be the least preferred option.

Well there is one more thing, not really a solution, but see if you can get away with Factory.build in your specs, instead of actually creating the object. (Would be the simplest if you can).

I’m not sure if it is the best solution, but I have successfully achieved this using:

FactoryGirl.define do
  factory :user do
    first_name "Luiz"
    last_name "Branco"
    #...

    after(:build) { |user| user.class.skip_callback(:create, :after, :run_something) }

    factory :user_with_run_something do
      after(:create) { |user| user.send(:run_something) }
    end
  end
end

Running without callback:

FactoryGirl.create(:user)

Running with callback:

FactoryGirl.create(:user_with_run_something)

When you don’t want to run a callback do the following:

User.skip_callback(:create, :after, :run_something)
Factory.create(:user)

Be aware that skip_callback will be persistant across other specs after it is run therefore consider something like the following:

before do
  User.skip_callback(:create, :after, :run_something)
end

after do
  User.set_callback(:create, :after, :run_something)
end

Calling skip_callback from my factory proved problematic for me.

In my case, I have a document class with some s3-related callbacks in before and after create that I only want to run when testing the full stack is necessary. Otherwise, I want to skip those s3 callbacks.

When I tried skip_callbacks in my factory, it persisted that callback skip even when I created a document object directly, without using a factory. So instead, I used mocha stubs in the after build call and everything is working perfectly:

factory :document do
  upload_file_name "file.txt"
  upload_content_type "text/plain"
  upload_file_size 1.kilobyte
  after(:build) do |document|
    document.stubs(:name_of_before_create_method).returns(true)
    document.stubs(:name_of_after_create_method).returns(true)
  end
end

This will work with current rspec syntax (as of this post) and is much cleaner:

before do
   User.any_instance.stub :run_something
end

This solution works for me and you don´t have to add an additional block to your Factory definition:

user = FactoryGirl.build(:user)
user.send(:create_without_callbacks) # Skip callback

user = FactoryGirl.create(:user)     # Execute callbacks

I’d like to make an improvement to @luizbranco ‘s answer to make after_save callback more reusable when creating other users.

FactoryGirl.define do
  factory :user do
    first_name "Luiz"
    last_name "Branco"
    #...

    after(:build) { |user| 
      user.class.skip_callback(:create, 
                               :after, 
                               :run_something1,
                               :run_something2) 
    }

    trait :with_after_save_callback do
      after(:build) { |user| 
        user.class.set_callback(:create, 
                                :after, 
                                :run_something1,
                                :run_something2) 
      }
    end
  end
end

Running without after_save callback:

FactoryGirl.create(:user)

Running with after_save callback:

FactoryGirl.create(:user, :with_after_save_callback)

In my test, I prefer to create users without the callback by default because the methods used run extra stuff I don’t normally want in my test examples.

A simple stub worked best for me in Rspec 3

allow(User).to receive_messages(:run_something => nil)

None of these solutions are good. They deface the class by removing functionality that should be removed from the instance, not from the class.

factory :user do
  before(:create){|user| user.define_singleton_method(:send_welcome_email){}}

Instead of suppressing the callback, I am suppressing the functionality of the callback. In a way, I like this approach better because it is more explicit.

James Chevalier’s answer about how to skip before_validation callback didn’t help me so if you straggle the same as me here is working solution:

in model:

before_validation :run_something, on: :create

in factory:

after(:build) { |obj| obj.class.skip_callback(:validation, :before, :run_something) }
FactoryGirl.define do
 factory :user do
   first_name "Luiz"
   last_name "Branco"
   #...

after(:build) { |user| user.class.skip_callback(:create, :after, :run_something) }

trait :user_with_run_something do
  after(:create) { |user| user.class.set_callback(:create, :after, :run_something) }
  end
 end
end

You could just set the callback with a trait for those instances when you want run it.