Problems with tests

Hi all

I'm trying to write good unit tests. Here's part of my blog_test.rb:

--- blog_test.rb:

require File.dirname(__FILE__) + '/../test_helper'

class BlogTest < Test::Unit::TestCase   fixtures :blogs,     :comments

  def setup     @valid_blog = Blog.new(valid_blog_attributes)   end

  def test_should_be_able_to_have_many_comments     @valid_blog.comments = {}     assert_valid @valid_blog

    comments.each do |comment|       @valid_blog.comments << comment       assert_not_nil @valid_blog.comments       assert_valid @valid_blog     end   end end

--- comments.yml:

first_comment:   id: 1   body: "Dies ist der Inhalt des ersten Kommentars"

second_comment:   id: 2   body: "Dies ist der Inhalt des zweiten Kommentars"

The Comment model is :polymorphic => true, :as => :commentable.

As we can see there are two comments available in the fixtures, but in when running the test_should_be_able_to_have_many_comments test, there are none!

puts comments.size

returns 0 all the time! Why aren't they available?

Thanks a lot for help. Josh

It seems that the fixtures are not correct (not complete). When I specify the commentable_type and _id, it works:

  commentable_type: "Blog"   commentable_id: 1

Why is that? I'd like to put the fixtures as loose as possible into the database and then hardwire them to the needed other objects in each test, so for the blog_test.rb I wanted to do:

  def setup     @valid_blog = Blog.new(valid_blog_attributes)     @valid_blog.comments << comments   end

...and I hoped that this would automatically set the commentable_type and _id to the needed values then.

But this doesn't seem so. So I guess I have to hardwire the stuff all in the fixtures... Or are there other, better ways to achieve better dynamics?

Why not test by creating comments - bypass the comments fixtures all together?

def test_should_be_able_to_have_many_comments   blog = blog.create!(valid_blog_attributes)   assert_difference "blog.comments" do     blog.comments.create!(valid_comment_attributes)   end end

what version of rails are you using?

Gavin wrote:

Why not test by creating comments - bypass the comments fixtures all together?

def test_should_be_able_to_have_many_comments   blog = blog.create!(valid_blog_attributes)   assert_difference "blog.comments" do     blog.comments.create!(valid_comment_attributes)   end end

what version of rails are you using?

On Apr 16, 10:46�am, Joshua Muheim <rails-mailing-l...@andreas-s.net>

Thanks, but I'm doing it now the hardwired way. :slight_smile:

Joshua Muheim wrote:

I'm trying to write good unit tests. Here's part of my blog_test.rb:

--- blog_test.rb:

require File.dirname(__FILE__) + '/../test_helper'

class BlogTest < Test::Unit::TestCase   fixtures :blogs,     :comments

  def setup     @valid_blog = Blog.new(valid_blog_attributes)

Don't construct a blog - fetch one from the fixtures:

       @valid_blog = blogs(:valid_blog)

  end

  def test_should_be_able_to_have_many_comments     @valid_blog.comments = {}     assert_valid @valid_blog

The assertion that the blog is valid should be in the setup or another test. Each test case should only speak to one activity.

    comments.each do |comment|

Where does comments come from? you are probably picking up comments(), which is the fixture loader. It returns an array unless you pass one comment, so you are now slipping off that array. Try this:

       comments(:first_comment, :second_comment).each do |comment|

      @valid_blog.comments << comment       assert_not_nil @valid_blog.comments

As you get better at testing, you will get bored with testing that ActiveRecord behaves as advertised, and you will test your actual logic.

To set a good example here, don't test against nil, because if comments were an empty array, then assert_not_nil would pass.

Instead, test that the comment went in:

         assert{ @valid_blog.comments.last == comment }

That illustrates two things. It shows my assert{ 2.0 }, which turns any expression into a generic assertion, and it shows AR evaluates == as true if two records have the same ID.

         assert{ @valid_blog.valid? }

    end   end end

--- comments.yml:

first_comment:   id: 1   subject: "Dies ist der erste Kommentar"   body: "Dies ist der Inhalt des ersten Kommentars"

If you use Rails >2, don't use the id: 1. Let the fixturizer build the number for you. This makes coding much simpler.

Next, don't call it first_comment. Name it after the theme of your comment.

Joshua Muheim wrote:

[...]

> def setup > @valid_blog = Blog.new(valid_blog_attributes)

Don't construct a blog - fetch one from the fixtures:

   @valid\_blog = blogs\(:valid\_blog\)

Why? In my experience, fixtures make tests brittle and hard to understand, so I've stopped using them entirely. What's the advantage here?

[...]

As you get better at testing, you will get bored with testing that ActiveRecord behaves as advertised, and you will test your actual logic.

Yeah. ActiveRecord has already been well tested. Focus on the code you wrote.

(I know, that's a tough concept to internalize -- I certainly don't always manage...)

To set a good example here, don't test against nil, because if comments were an empty array, then assert_not_nil would pass.

Instead, test that the comment went in:

     assert\{ @valid\_blog\.comments\.last == comment \}

That illustrates two things. It shows my assert{ 2.0 }, which turns any expression into a generic assertion,

[...]

Cool! Sexy RSpecish syntax for the unsexy Test::Unit! I'll have to try it out! :stuck_out_tongue:

(Seriously, I think assert2 looks great, and I'm looking forward to trying it.)

Best,

Marnen Laibow-Koser wrote:

  def setup     @valid_blog = Blog.new(valid_blog_attributes)

Don't construct a blog - fetch one from the fixtures:

       @valid_blog = blogs(:valid_blog)

Why? In my experience, fixtures make tests brittle and hard to understand, so I've stopped using them entirely. What's the advantage here?

(Let's hope you have not replaced them all with totally empty mocks!)

The advice for newbs, and possibly also for the original poster, is to use fixtures the way the tutorials specify. This gets them out of the starting gate.

The advice, as a project grows, is to use some form of "scenarios", which are kits of fixtures tuned to specific situations. Example: new_customer, paid_up_customer, delinquent_customer, etc.

If you don't use raw fixtures, you should find yourself implementing a scenario system directly into your setup blocks. From there, you should re-use their support methods into some scenario library.

Finally, I suspect the most advanced advice possible is to always write assertions that gracefully adapt to your data records, whether they be classic range-free fixtures, or isolated scenarios. Don't do this:

   records = get_fithy_records()    assert{ records.length == 17 }

That breaks when you add a new filthy record, for whatever reason! Instead, do this:

   assert{ records.map(:status).uniq == ['filthy'] }

This link emblogs the ideal of writing flexible tests, even when your code happens to implement something complex, such as a Minimum Spanning Tree:

As you get better at testing, you will get bored with testing that ActiveRecord behaves as advertised, and you will test your actual logic.

Yeah. ActiveRecord has already been well tested. Focus on the code you wrote.

(I know, that's a tough concept to internalize -- I certainly don't always manage...)

When you are getting started with a new library, writing unit tests directly on the library is a best practice. So, you should indeed precede "Foo.has_many :bars" with a test that a foo object has a .bars collection full of bars.