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 < 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 << 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 < 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
after_create
is called, well, after the record's been persisted. So a failure in the notification mailer shouldn't affect it. \$\endgroup\$User.first.teams << Team.first
and thatafter_create
action raised an error, theTeamMembership
record does not seem to get persisted. \$\endgroup\$test_notifier.verify
without the assert) \$\endgroup\$