new differences in assert_difference

— June 4, 2007 at 01:36 PDT


Last month I wrote about the new assert_difference test helper and how to use it to test any kind of difference using lambdas. Since then there have been a couple changes to assert_difference that make it easier for doing this sort of thing. Yes, this is life on the edge. Things change, sometimes faster than a humbler blogger can keep up with.

The first big change was that instead of an object and a method, assert_difference now takes a string that gets eval'ed. The second change is that it doesn't just take one string, it takes an array of strings that get eval'ed. And it's important to note that the strings are eval'ed in the binding scope of assert_difference block, so they will have access to variables that are set in the block.

Here's my previous example:

def test_create_user
  login = "bob"
  name = "Bob Dobbs"
  assert_difference( lambda { User.find_all_by_login(login).size }, :call, 1 ) do
    bob = User.create!(:login => login, :name => name)
    assert_equal login, bob.login
    assert_equal name, bob.name
  end
end

Here's how to do that in the new way:

def test_create_user
  login = "bob"
  name = "Bob Dobbs"
  assert_difference( 'User.find_all_by_login(login).size', 1 ) do
    bob = User.create!(:login => login, :name => name)
    assert_equal login, bob.login
    assert_equal name, bob.name
  end
end

And if you want to make sure the user's mailbox is created at the same time:

def test_create_user
  login = "bob"
  name = "Bob Dobbs"
  assert_difference( ['User.find_all_by_login(login).size', 'Mailbox.count'], 1 ) do
    bob = User.create!(:login => login, :name => name)
    assert_equal login, bob.login
    assert_equal name, bob.name
    assert_not_nil bob.mailbox
  end
end

The difference defaults to 1 so you don't really need to specify it, but I like seeing it there all explicit and obvious. YMMV.

I find this change interesting. On the one hand, it makes everyone who was using the old style helper change their code. This helper was floating around for a long time before getting included into core, so a lot of people are going to have to update. What a pain. On the other hand, I like the extra flexibility. My preference is to use a lambda instead of an eval'ed string, but I can see how the lambda syntax is a bit unwieldy for this use. I've seen some of the ideas for a more compact syntax for lambdas in a future Ruby, and this is a great example of a place where that would be useful. I think if we had a two-character lambda notation, we'd be seeing lambda's here instead of eval'ed strings. (Pretend I just inserted a clever comparison with Smalltalk blocks and why they are so easy to use. If you need it for real, feel free to make it up yourself.)

0 comments — [none]

Comments

Sorry, comments for this article are closed.