Sometimes a test case must detect when production code creates new records, as a side-effect. assert_latest{} detects all new records of a given type, and returns them like this:

    f1, f2 = assert_latest Foo do
               2.times{ Foo.create }
             end

    assert 'items return ordered by id' do
      f1.id > 0 and f2.id > f1.id
    end

This post shows how to use assert_latest{} in more advanced configurations. It can detect records of more than one type, and can detect records that belong to only one association. Our platform is Ruby on Rails, yet - as usual - the lessons apply to any unit tests.

Our tool list includes the usual suspects:

The assert_latest system uses assert_efficient_sql - review its blog entry here.

Get the latest version with gem install assert_efficient_sql.

Plurality

Start by adding this to one of your test suites or specifications:

require 'assert_efficient_sql'

A real project would naturally write tests that call production code, possibly with nested and hidden creation lines. To illustrate assert_latest{} in action, we will first sample from its own unit tests. These call no production code; they simply concoct two models, Foo and T2, and then experiment by constructing them.

This test shows how assert_latest can return two types at once:

    t, fz = assert_latest T2, Foo do
              T2.create
              2.times{ Foo.create }
            end

    assert do
      t.id > 0     and
      fz[0].id > 0 and
      fz[1].id > fz[0].id
    end

The assertion returned an array containing the one first item, and a nested array with the two second items. Essentially [ t, [ fz1, fz2 ] ]. If the system found only one Foo, it would have returned [ t, fz1 ], without the nested array. The following assertions will implicitly test the new records’ plurality simply by using them. If production code only created one Foo, then fz[0] would fail.

(Also note that real tests would assert something more useful than a populated .id field!)

Fault Diagnostics

To accelerate development, assertion diagostics should take care to declare what went wrong. This test case shows assert_latest failing to create T2 records:

    assert_flunked /diagnostic.*new T2 record/m do
      f, t = assert_latest Foo, T2, 'diagnostic' do
               Foo.create
             end
    end

The assert_flunked detects the assertion raised an error containing your custom ‘diagnostic’ text, and the verbiage “should create new T2 record(s)”. assert_latest{} also decorates its faults with the reflected source of its block, using the RubyReflector system from assert{ 2.0 }.

Denial

Most generic assertions should have a matching denial. This test trivially reveals the contrapositive of the last test:

    assert_flunked /diagnostic.*new Foo record/m do
      f, t = deny_latest Foo, T2, 'diagnostic' do
               Foo.create
             end
    end

Note the diagnostic now complains that your production code should not have created a new Foo record.

Who’s your Daddy?

assert_latest’s arguments do not need to be raw models. They can be anything that responds to .maximum and .find. So the more you tell assert_latest, the more accurate results.

This example works with rboard, a blog by Radar:

    user = users(:plebian)
    topic = topics(:user_2)

    p1, p2 = assert_latest user.posts, topic.posts do
      user.posts.create :topic => topic,
                 :text => 'Vote McBush, early and often!'
    end

    assert{ p1.id == p2.id }

The test uses two associations, so it cross-tests both parents of the new Post. A new record with a different user and topic cannot accidentally pass the test.

Polygamous and explicitly-associated assert_latest{} blocks work great in integration tests and end-to-end tests. Short test cases must call a whole lot of code, and then assert that all of it created only the correct output records. assert_latest{} lets you list exactly what you expect, without redundant lines in your test case, just to look up and inspect the created records.