# Problems with tests

**URL:** <https://www.ruby-forum.com/t/problems-with-tests/165675>\
**Category:** Rails\
**Created:** [April 16, 2009, 11:23am UTC](https://www.ruby-forum.com/t/problems-with-tests/165675 "2009-04-16T11:23:00Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 11:23am UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/1 "2009-04-16T11:23:00Z")

</div>

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  
subject: “Dies ist der erste Kommentar”  
body: “Dies ist der Inhalt des ersten Kommentars”

second\_comment:  
id: 2  
subject: “Dies ist der zweite Kommentar”  
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

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 11:46am UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/2 "2009-04-16T11:46:47Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 1:05pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/3 "2009-04-16T13:05:44Z")

</div>

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 M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 3:08pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/4 "2009-04-16T15:08:29Z")

</div>

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 M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

Thanks, but I’m doing it now the hardwired way. 🙂

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 3:42pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/5 "2009-04-16T15:42:00Z")

</div>

Joshua M. 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)

```

> 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.

–  
Phlip

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 5:11pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/6 "2009-04-16T17:11:05Z")

</div>

Thanks for your useful hints, Philip.

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 5:31pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/7 "2009-04-16T17:31:35Z")

</div>

On Apr 16, 9:37 am, Phlip [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Joshua M. 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! 😛

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

## Best,

Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 16, 2009, 8:39pm UTC](https://www.ruby-forum.com/t/problems-with-tests/165675/8 "2009-04-16T20:39:37Z")

</div>

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:

> **[Radar - O’Reilly](https://www.oreilly.com/radar/)**
>
> Now, next, and beyond: Tracking need-to-know trends at the intersection of business and technology

> > 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.

–  
Phlip  
[http://flea.sourceforge.net/resume.html](http://flea.sourceforge.net/resume.html)
