a better assert_difference

Courtenay : June 13th, 2006

In case you haven't seen it, assert_difference from 37s' Marcel Molina has a handy test function : (again!). Actually there are a few different versions out in the wild.. the original is from http://project.ioni.st/post/218#post-218


def test_adds_a_group
  assert_difference Group, :count do
    post :create, :group => { :name => 'monkeys' }
  end
end
However, once you start nesting these they look like ass.


def test_membership
  assert_difference Group, :count do
    assert_difference User, :count do
      Membership.create(:group_id => 1, :user_id => 2)
    end
  end
end

Here's a new way of doing it...

def test_membership
  assert_difference [ User, Group ], :count do
    Membership.create(:user_id => 1, :group_id => 5)
  end
end

or even
test_changes_name
  assert_difference User, :name, nil do
    post :update, :id => 5, { :name => 'monkeys' }
  end
end
paste this into your test\_helper and replace existing assert\_difference as necessary :) It's backwards compatible. And it takes strings!


  def assert_difference(objects, method = nil, difference = 1)
    objects = [objects].flatten
    initial_values = objects.inject([]) { |sum,obj| sum << obj.send(method) }
    yield
    if difference.nil?
      objects.each_with_index { |obj,i|
        assert_not_equal initial_values[i], obj.send(method), "#{obj}##{method}"
      }
    else
      objects.each_with_index { |obj,i|
        assert_equal initial_values[i] + difference, obj.send(method), "#{obj}##{method}"
      }
    end
  end

5 Responses to “a better assert_difference”

  1. Jarkko Laine Says:
    Courtney, That's way cool. However, I found one bug in it. I often want to test the difference in a container, say for example the :size of @group.members (where members is either a has_many or habtm association), which is an array. Now, because you flatten the array, it doesn't work anymore, because the size method is called on the member object, not the array of members.
  2. topfunky Says:
    I second Jarkko's wish. I'm working on a version that takes a proc for the count and calls it. Theoretically you could drill down that way.
  3. Nathan Says:

    Thanks for the tests and ideas it gave me for further test helper development. I wanted to post a quick note about how I’ve extended this particular test to work slightly better for cached instance values.

    I find myself occasionally testing to be sure some computed value has changed (counter_cache for instance, although there are several others). So, I simply added:

    obj.reload if obj.respond_to?(:reload)

    before both assertions (assertnotequal, assert_equal) to be sure obj.send returns any updated values.

    Thanks again!

  4. ifojenvnhryuiyfbe Says:

    Buy Viagra Viagra pill Viagra Online Viagra Soft Tabs Cheap Viagra BUY CIALIS Paxil Online Buy Viagra Viagra pill Viagra Online Viagra Soft Tabs Cheap Viagra BUY CIALIS Paxil Online

  5. Noah Morais Says:

    Very useful information was found here, thank you for your work.

Sorry, comments are closed for this article.