Testing eager loading of associations

Is there an easy way to test to see if an association has been loaded by eager-loading
already? I’d like to detect (in functional tests) that comments are
eager-loaded when a Post is selected. I can do

assert post.instance_variables.include?
("@comments")

but is that appropriate?

Any ideas? Thanks much!

Brian,

  > Is there an easy way to test to see if an association has been loaded by
  > eager-loading already? I'd like to detect (in functional tests) that
  > comments are eager-loaded when a Post is selected. I can do

(not an answer:)
It looks like you are trying to test the framework (Rails). May I ask why?

Alain

Brian Hogan wrote:

Is there an easy way to test to see if an association has been loaded by eager-loading already? I'd like to detect (in functional tests) that comments are eager-loaded when a Post is selected. I can do

  assert post.instance_variables.include? ("@comments")

but is that appropriate?

Yes, that'd work. Also: assert post.comments.loaded?

Alain Ravet wrote:

Brian,

  > Is there an easy way to test to see if an association has been loaded by
  > eager-loading already? I'd like to detect (in functional tests) that
  > comments are eager-loaded when a Post is selected. I can do

(not an answer:)
It looks like you are trying to test the framework (Rails). May I ask why?

He's probably ensuring that the include option has been correctly programmed.

That should be covered by Rails unit tests.

@luke:

No, I’m testing to ensure that my developers have eager-loaded associations in some controller methods. I want the functional tests to fail if they forgot to eager-load.

We’re doing test-first development here so the devs know when they need to eager-load. I just wanted a way for them to test that they did.

Testing

@post = Post.find params[:id]

vs

@post = Post.find params[:id], :include=>[:comments]

Or in a bigger case

def self.find_projects_and_associations
Project.find params[:id], :include=>[{:tasks =>:hours}, :notes, :attachments, :backlogtasks, :payments, :expenses]

end

A call like this would go into the model… but a developer still has to use it. If they use a regular finder.

So I’m not testing to see if eager loading works, I’m testing to see if the developer used it :slight_smile:

@Mark:

Thank you!

Brian

  > No, I'm testing to ensure that my developers have eager-loaded associations
  > in some controller methods. I want the functional tests to fail if they
  > forgot to eager-load.

If your system is too slow, then build a test that fails at the
current speed, and tell them that one way to make the test pass is too
eager load.
In the absence of context, it looks like micro-managing and premature
optimization.

  > We're doing test-first development here so the devs know when they need to
  > eager-load. I just wanted a way for them to test that they did.

Well No: they don't know they NEED it - there is no failing test- ,
they just know that they HAVE TO write code that way, for some reason.

Alain

@Alain:

If your system is too slow, then build a test that fails at the
current speed, and tell them that one way to make the test pass is too
eager load.
In the absence of context, it looks like micro-managing and premature

optimization.

I disagree. There are times when you know you’re going to cause 200+ queries if you don’t eager load. Testing for those cases is, IMHO, not micromanaging or premature optimization.

Brian,

> If your system is too slow, then build a test that fails at the
> current speed, and tell them that one way to make the test pass is too
> eager load.

..

I disagree. There are times when you *know* you're going to cause 200+
queries if you don't eager load. Testing for those cases is, IMHO, not
micromanaging or premature optimization.

My point is that you are NOT testing that you are solving a
(potential!) problem. You're JUST ensuring that you have implemented
one possible solution.
You check that the patient takes his vitamins, but not that they are
effective, or even needed.
And why only test eager-loading? What about indexes? Will you test the
schema, to see if they have addedan index on all/a given column. And
what about Caching, Custom selects, Memoizing, etc..
If you write real functional speed/benchmark tests, they will test
your eager-loading/caching/indexing needs indirectly.

Alain

I see ensuring the eager load via a test as a way to verify a spec - I
have many actions or associations that I know I *always* want to eager
load. The right place for that is in a live spec, ie a test case or
rspec context. That certainly doesn't remove the need for real
performance testing and benchmarking - but often proper eager loading
is the simplest thing that works, and the really nasty cases that need
more tuning will be clear after that.

- Rob

Rob:

Exactly! Thanks!

Rob

  > I see ensuring the eager load via a test as a way to verify a spec - I
  > have many actions or associations that I know I *always* want to eager
  > load.

I see no difference between adding eager-loading, and adding an index
to a table. Do you test the schema for index presence?
When I notice an application is slow, and I see it's due to a missing
index, I just add the index in a migration, and that's it. If the
application is still slow, then I add a functional benchmark test, and
I start experimenting.

And I have this funny feeling about checking the implementation, and
not the end-result/interface..

  > often proper eager loading is the simplest thing that works, and
the really nasty
  > cases that need more tuning will be clear after that.

I suspect there are cases where unnecessary eager-loading could
actually slow down an operation. The patient takes a double-dose of
his pills, but he's getting worse. As you are not testing his health
(speed), how do you know your cure is not worse than no cure? Or not
better?

Alain

I see no difference between adding eager-loading, and adding an index
to a table. Do you test the schema for index presence?
When I notice an application is slow, and I see it's due to a missing
index, I just add the index in a migration, and that's it. If the
application is still slow, then I add a functional benchmark test, and
I start experimenting.

Yes, actually I would test the indexes if I had a good way to do it.
Its a shame that testing the DB and schemas isn't taken more seriously
and easier to do with our tools. I know Glenn Vanderburg has done
talks on testing migrations
(http://glu.ttono.us/articles/2006/06/24/glen-vanderburg-testing-migrations),
and Scott Ambler talks alot about testind and refactoring your db, and
has a book on it as well.

So my lack of testing the schema is more due to a hole in my knowledge
then any lack of will. :slight_smile:

And I have this funny feeling about checking the implementation, and
not the end-result/interface..

I said we test both - low level tests of the association, plus
functional tests for overall speed, plus integration tests.

cheers,
Rob

@Alain:

Benchmarking your app is fine, but prevention where it makes sense is really important.

I see no difference between adding eager-loading, and adding an index
to a table. Do you test the schema for index presence?
When I notice an application is slow, and I see it’s due to a missing
index, I just add the index in a migration, and that’s it. If the

application is still slow, then I add a functional benchmark test, and
I start experimenting.

/puts on DBA hat…

Simply adding an index is a terrible way to improve performance unless you know WHY the query is slow. If a developer inadvertently executes 201 sql queries, exactly how is the addition of an index going to solve that? The individual record lookups might be faster but the real problem is the lack of left-joins.

By defining indexes you improve database performance by making it faster to find and sort the information stored in a table. While indexes speed up your reads, they can really slow down your inserts and updates. Indexing is really a science and it’s not something you just do because “indexes make my app run faster.” They can impact a lot of things and an index on one column may speed up some queries and slow down others.

Sorry, again, don’t mean to be difficult… I’m enjoying this conversation and you have given me much to think about.