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.