wholemeal

Chunky | Goodness

Assert Difference With Multiple Count Values

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

Rendering From a Model in Rails 3

Despite the plethora of advice available on the net to never, ever, ever render in a model, I still think there are occasional requirements to do so.

Here’s one way to do it in Rails 3:

class MyModel < ActiveRecord::Base
  # Use the my_models/_my_model.txt.erb view to render this object as a string
  def to_s
    ActionView::Base.new(Rails.configuration.paths.app.views.first).render(
      :partial => 'my_models/my_model', :format => :txt,
      :locals => { :my_model => self}
    )
  end
end

Making a ChangeLog With Git and Automake

Here’s my solution to this, based upon the solution from Erik Hjortsberg.

This will only get called by make dist or make distcheck and will only get updated when configure.ac gets updated, which is where I increment my release version numbers.

# In the top level Makefile.am
dist-hook: ChangeLog

ChangeLog: configure.ac
    git log --stat --name-only --date=short --abbrev-commit > ChangeLog