views:

137

answers:

2

In the Hibernate world, you can often have unit tests that appear to pass but there are actually bugs that don't show up because you're dealing with cached data. For example, you may save a parent with its children thinking it's cascading the save. If you re-query for the parent after the save and test the size of the child collection, it looks ok. But in reality Hibernate didn't save the children but cached the parent so you're looking at the un-saved children. One way to get around this is to clear the session cache between the save and the query so you know the data is coming straight from the database.

Is this an issue with ActiveRecord? If I save a model and then query it in the same test, is it possible that I'm not actually getting the data from the database but rather from the query cache? I haven't seen any sample tests that try to deal with this so I'm wondering if there's something that makes it a non-issue?

A: 

I have never run into this as an issue with ActiveRecord. My understanding is that the cache is only on reads, so saves are always performed.

Toby Hede
+1  A: 

Yes. Depending on how you write your tests the Rails query cache can sometimes interfere. Sometimes rails is smart enough to keep track of when the cache needs to be cleared (When there is an obvious association between objects), but here is an example that would not behave as expected:

user.posts.should == []
Post.create(:user_id => user.id)
user.posts.size.should_not == [] # Fails, since the original query was cached.

In general, if you are executing the same query twice in the same test you should call .reload on the data prior to attempting to executing the second query. Like so:

user.posts.should == []
Post.create(:user_id => user.id)
user.posts.reload
user.posts.size.should_not == []

In my personal experience it is better to consider a different way of writing the test than to use the method above. For example, here's a better way of writing the above that will not be affected by the query cache:

lambda { Post.create(:user_id => user.id) }.should_change(user.posts, :count).by(1)

Gdeglin