assert_difference
is a really useful assertion baked in to Rails. It allows you to check that a value has changed by a given amount after a block has been executed.
Here’s a pretty common use case, check a comment gets created in your CommentsControllerTest
:
# Make sure one new comment is created
assert_difference 'Comment.count', 1 do
post :create, :comment => @comment_attributes
end
You can also check that several different values change by a given amount:
# Make sure one new comment and one notification email is created
assert_difference ['Comment.count', 'ActionMailer::Base.deliveries.size'], 1 do
post :create, :comment => @comment_attributes
end
But, you cannot check if multiple values change by difference amounts, i.e. check that 1 comment and 2 notification emails get created.
The following method will allow you to do just that, drop it into test/test_helper.rb
and you’re away.
# Runs assert_difference with a number of conditions and varying difference
# counts.
#
# Call as follows:
#
# assert_differences([['Model1.count', 2], ['Model2.count', 3]])
#
def assert_differences(expression_array, message = nil, &block)
b = block.send(:binding)
before = expression_array.map { |expr| eval(expr[0], b) }
yield
expression_array.each_with_index do |pair, i|
e = pair[0]
difference = pair[1]
error = "#{e.inspect} didn't change by #{difference}"
error = "#{message}\n#{error}" if message
assert_equal(before[i] + difference, eval(e, b), error)
end
end