Testing after_save hooks in Rails 4.2 with MiniTest I've recently started working on a new application in Rails 4.2.0-beta2. I've been using this as an opportunity to learn more about MiniTest, with a stretch goal of being as strict with myself with testing as possible.

My general problem: How do I test the after_save action for an ActiveRecord model in such a way that I can be confident that an ActiveRecord callback will not cause my code to break?

Here's what I've got so far (gist or inline code below).

How would you (re)write these files to detect if the NotificationMailer called in the after_save hook prevented a TeamMembership from being persisted?

Note that not included here are the relevant test fixtures. You may safely assume that fixtures users(:carol) and teams(:alpha) are not associated with each other.

app/models/team_membership.rb

class TeamMembership &lt; ActiveRecord::Base
  # A proc that will enqueue `NotificationMailer.team_invitation`
  DEFAULT_NOTIFIER = proc do |user, team|
    NotificationMailer.team_invitation(team, user).deliver_later
  end

  class &lt;&lt; self
    # This is a class level attribute that is mainly used for testing.
    # Defaults to {TeamMembership::DEFAULT_NOTIFIER}
    attr_accessor :notifier
  end
  self.notifier = DEFAULT_NOTIFIER

  belongs_to :team
  belongs_to :user

  after_create :invite_user_to_team!

  private

  # ActiveRecord callback used to equeue team invitation emails
  # @return void
  def invite_user_to_team!
    self.class.notifier.call(team, user)
    nil
  end
end


tests/models/team_membership_test.rb

require 'test_helper'

class TeamMemberTest &lt; ActiveSupport::TestCase
  test 'callbacks' do
    # setup
    test_notifier = Minitest::Mock.new
    test_notifier.expect(:call, nil, [teams(:alpha), users(:carol)])
    TeamMembership.notifier = test_notifier

    # test
    TeamMembership.create(user_id: users(:carol).id, team_id: teams(:alpha).id)
    assert test_notifier.verify

    # teardown
    TeamMembership.notifier = TeamMembership::DEFAULT_NOTIFIER
  end
end
A valid approach would be check if NotificationMailer.team_invitation was called. In order to get this job done, you'll need first of all change this NotificationMailer.team_invitation hard-coded call to something injected. Something like this:

class TeamMembership &lt; ActiveRecord::Base
  # other methods

  after_create :invite_user_to_team!

  def notification_method(notification_service = NotificationMailer)
    @notification = notification_service
  end

  private
  def invite_user_to_team!
    @notification.team_invitation(team, user)
    nil
  end
end


Now, you can create an expectation over NotificationMailer. Inside your test, you can define your mock and define its behavior:

class TeamMemberTest &lt; ActiveSupport::TestCase
  def test_after_create_new_team_member_it_should_be_notified
    notification = Minitest::Mock.new
    notification.expects(:team_invitation).with(team, user).once
    # your TeamMember class working to create new
  end
end


I hope it helps :)