Assertion doesn't make sense (to me)

Hi, I am just starting out writing unit tests, and perhaps someone could
be kind enough to explain why I am seeing this behaviour:

First, my model looks like this:

Author <-HABTM-> Paper

With a model named ‘authors_papers’ which belongs_to :author and :paper.
This is to act as a lookup table which I believed Rails would do
automatically if set up like this.

This is my testing code, testing the Author model:

# Tests the Author<->Paper linkage through the automatic use of
    # the author_papers model by Rails.
    a = Author.new
    p = Paper.new
    assert_not_nil a
    assert_not_nil p
    assert a.save
    assert p.save

    # 1. Does the linkage work, returning an empty set?
    assert_equal a.papers, []

    # 2. Can we assign a paper to the author?
    assert a.papers << p
    assert a.save
    assert_not_equal a.papers, []

    # 3. Can we pull that paper out (read) again?
    assert a.papers.include?(p)

    # 4. Can we find the author from the paper?
    assert_not_nil p.authors
    assert p.authors.include?(a)

    # 5. Can we update through the link?
    assert p.authors.first.update_attributes(:lastname => "abc") #
Succeeds
    assert_equal("abc", p.authors.first.lastname)                #
Succeeds
    puts "A.Lastname: #{a.lastname}"                             # =>
<nil>
    puts p.authors.first.lastname                                # =>
abc
    assert_equal a, p.authors.first                              #
Succeeds
    assert_equal("abc", a.lastname)                              #
Fails!

The problem is in the last assertion - surely a.lastname should be set
to ‘abc’ as we did that through the relationship from the Paper? Any
help would be much appreciated, thanks.

On 5 Oct 2007, a

Succeeds
assert_equal(“abc”, a.lastname) #
Fails!

[/code]

The problem is in the last assertion - surely a.lastname should be set
to ‘abc’ as we did that through the relationship from the Paper? Any
help would be much appreciated, thanks.

The problem is that a contains stale data (it corresponds to the same
row in the database as p.authors.first, but it’s a different ruby
object(.
If you did a.reload before the assertion, the test should pass. The
compare on active record just compares the primary key, not the
attributes, which is why assert_equal a, p.authors.first

Fred

The problem is that a contains stale data

Aha - I had suspected it was something like this but my unfamiliarity
with Rails prevented me from discovering the actual culprit.

Thanks a lot for your time taken, it’s much appreciated,

  • N

Peter L. wrote:

First, my model looks like this:

Author <-HABTM-> Paper

With a model named ‘authors_papers’ which belongs_to :author and :paper.
This is to act as a lookup table which I believed Rails would do
automatically if set up like this.

In addition to other comments…

If by “Model” you mean a first-class object with more variables than
just the two IDs, you shouldn’t use has_and_belongs_to_many. You
should use:

class Author…
has_many :authors_papers
has_many :papers, :through => :authors_papers

This implies you should give authors_papers.

However, if you said “Model” because you mean “table”, and that table
owns no data for itself, then use habtm!

This is my testing code, testing the Author model:

This test case is too long. Short test cases are the key to happiness.

[code]

Tests the Author<->Paper linkage through the automatic use of

# the author_papers model by Rails.
a = Author.new
p = Paper.new

Those should be in the fixture system.

assert_not_nil a
assert_not_nil p

Don’t assert something if another line will incidentally assert it.
And we wouldn’t get very far in this test if either of those were nil.

And give them complete names.

assert a.save
assert p.save

By and large tests should save with save!. That satisfies the
assertion concept by exploding if it can’t save. Further, save! will
emit a diagnostic declaring why we could not save, and ‘assert’ will
only say “false is not true”.

# 1. Does the linkage work, returning an empty set?
assert_equal a.papers, []

Yes it’s harmless to add assertions that learn how Rails plumbing works!

# 2. Can we assign a paper to the author?
assert a.papers << p
assert a.save
assert_not_equal a.papers, []

Would this work?

assert_equal [p], a.papers

I suspect you can force a reload on a collection by passing (:reload)
to its successor. I have not confirmed this, so someone must speak up
if I’m wrong!

In general, prefer positive statements to negative ones, including
positive “assert_equals” instead of negative “assert_not_equal”.

I also suspect one can pass (true), but that’s not self-documenting.

Also, you should put the “reference” on the left side of an assertion,
and the “sample” on the right. There are numerous trivial reasons to
do this; just do it because there are no good reasons to put the
reference on the right!

# 5. Can we update through the link?
assert p.authors.first.update_attributes(:lastname => "abc") #

Succeeds

Thanks for the reminder that I should tack assert onto the beginning
of all my test cases’ update_attributes calls!

Now that you have experienced the joy of writing assertions for
behavior that’s already written, you are going to have major fun
writing tests for your own new code. More fun than endless debugging,
at least!


Phlip
http://www.oreilly.com/catalog/9780596510657/
^ assert_xpath

Phlip - thanks for you comments, will help me improve my testing a great
deal.

  • N