Testing ActiveRecord Callbacks With RSpec3

written

Theses days, I don’t have much chance to use ActiveRecord callbacks in my web applications, but sometimes it’s still useful to use those callbacks. I post how to test ActiveRecord callbacks such as after_save or after_create with RSpec version 3.x syntax so as not to forget.

Let’s say we have User model.

1
2
3
class User < ActiveRecord::Base

end

And then, we added after_create callback method to this model.

1
2
3
4
5
6
7
8
class User < ActiveRecord::Base

  after_create :send_email

  def send_email

  end
end

Now, how can I assure that this send_email method is called by using RSpec?

First option is to call run_callbacks method. run_callbacks method is from ActiveSupport. It runs the callbacks for the given event.

So we can stub like,

1
2
3
4
5
6
7
8
9
10
11
12
RSepc.describe User, type: :model do
  # using factory_girl
  let(:user) { build(:user) }

  describe '#send_email' do
    it 'fires send_email method as after_create method callbacks' do
      expect(user).to receive(:send_email)
      user.run_callbacks(:create)
    end

  end
end

With using run_callbacks method, we are expecting the user instance to be called send_email method.

NOTE: expect(something).to receive(:bar) is equivalent to the should_receive method in RSpec 2 syntax

Second, and probably the better option is to use the shoulda-callback-matchers gem.

Those who familer with shouda-matchers gem might think that this gem is extension of shoulda-matchers, but this shoulda-callback-matchers is not from thoughtbot, and probably not the extension of shoulda-matchers.

Usage of this gem is pretty much like shoulda-matchers. Let’s take a look.

1
2
3
4
describe Post do
  it { is_expected.to callback(:count_comments).before(:save) }
  it { is_expceted.to callback(:post_to_twitter).after(:create) }
end

Easy!

One of the nice things of this gem is that the sentence itself is clearly straight forward and readable. You can understand the code as soon as you take a look.

Though, this gem has not much users and github stars, it is still on maintenance.(@2014/9/5) It will be much easier to test callbacks if you use this gem than using run_callbacks method.