ANN: nu_record = assert_latest(Model){ create_some_model()

Railsters:

A recent question here asked how to get the ID of a recently added Model
object. (The answer is that methods like .create and .save populate the
.id
field.)

This leads to a new question: How can a test detect the most recently
added
record? The best way is for “unit test” code to directly call methods
who
create the record, and they should return it.

Sometimes that’s not so easy. Controller tests, for example, only return
their @ instance variables in their assigns[] hash, and a controller
that
creates model objects might not have a good reason to assign and
remember
them.

To cover these situations (and to respond to several needs in my current
project), I invented two new assertions:

  • assert_latest(Model, message = nil, &block)
  • deny_latest(Model, message = nil, &block)

Both take…

  • Model - an ActiveRecord class, such as User, Chat, etc…
  • message - optional string to prefix any flunk messages
  • block - a required closure to call the tested code

The assert_ passes, and the deny_ fails, if any new record got created
in
that Model.

Here’s a test that checks we allow a user to sign up:

def test_should_allow_signup
user = assert_latest User do
create_user(:login => ‘phlip’)
assert_response :redirect
assert_redirected_to ‘http://test.host/phlip
end
assert_equal ‘phlip’, user.login
end

(Heck - my programs had better allow /me/ to sign up!!)

And here’s code to prevent a bogus signup attempt from creating a new
User
record:

def test_should_require_login_on_signup
deny_latest User do
create_user(:login => nil)
assert assigns(:user).errors.on(:login)
assert_response :success
end
end

Below my sig is a bio-plugin. Simply copy it into your test_helper.rb
file,
inside its main class there, and add assert_latest and deny_latest to
every
test that creates something - or should not!

Note that the code could not simply find the highest ID currently in use
and
simply add 1. A database table remembers an internal “Max ID” value, and
always increments this. Other test cases may create and delete records;
each
bumps this “high water mark” up. So the implementation must find the
lowest
new ID that’s higher than the maximum stored in any record.

The committee would be interested to hear if any rare arcane databases
out
there fail this system.


Phlip
http://www.oreilly.com/catalog/9780596510657/
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

def assert_latest(model, message = nil, &block )
return get_latest(model, &block) ||
flunk_latest(model, message, true)
end

def deny_latest(model, message = nil, &block)
get_latest(model, &block) and
flunk_latest(model, message, false)
end

def get_latest(model)
max_id = model.maximum(:id)
yield

return model.find( :first,
                   :conditions => "id > #{max_id}",
                   :order => "id desc" )

end

def flunk_latest(model, message, polarity)
message = if message then “#{message}\n” else ‘’ end
message += 'a new ’
message += model.name
message += ’ record should ’
message += 'not ’ unless polarity
message += ‘be created’
flunk(message)
end