Testing ActiveRecord Callbacks
I’m not a big fan of ActiveRecord callbacks – it usually seems like a quick-and-easy solution, but in the long term it makes testing difficult and can often create unexpected side-effects. However, sometimes there really is no other option which means we need to test these callbacks!
One way of testing the callbacks is to invoke the run_callbacks method.
describe 'after save callbacks' do
it 'should create a price' do
product = Product.new
product.prices.should_receive(:create)
product.run_callbacks(:after_save)
end
end
However, this no longer seems to work in the latest version of RSpec – you will receive this error: NoMethodError: undefined method `_run_before_save_callbacks’
The API has changed slightly – you can now either run only the before_save callbacks, or run both the before_save and after_save callbacks.
To run only the before_save callbacks:
product = Product.new
product.run_callbacks(:save) { false }
To run both the before_save and after_save callbacks:
product = Product.new
product.run_callbacks(:save) { true }
However, I would argue that invoking the individual callbacks in this way is not the best way of testing the callbacks. I much rather prefer to define a private method for the callback and then invoking the private method.
class Product < ActiveRecord::Base
after_save :create_price
private
def create_price
# create the price here
end
end
In this case, we can test the create_price method individually - still messy, but cleaner in my opinion.
describe '#create_price' do
it 'should create a price' do
product = Product.new
product.prices.should_receive(:create)
product.send(:create_price)
end
end
Of course, the best solution is to avoid callbacks altogether. Happy coding.