Testing Scopes in Rails3
A while back there seemed to be this secret programming war going on… how do we test named_scopes?
It came down to the type of tester that you were. You could build out the ActiveRecord objects you needed and assert that when the scope was called, the correct objects were returned. Or you could call the scope and assert that the #proxy_options (conditions) you expected to be passed were there. The latter, to me, seemed to be the better option. You would have faster tests because there was no database calls due to the creation of objects and you would only be testing your implementation of the scope… not ActiveRecord.
Well here we are now with Rails3 and all of those #proxy_options calls are busted. There is no #proxy_options method defined on the ActiveRecord::Relation class, which is what all scopes are now. What is a guy to do?
I have found a another option that I don’t really like but will explain. You can now call #to_sql on your finder to get the SQL that would be executed. So with that being said you could assert, with a regular expression, what the query should be firing with. To me this option seems a bit messy but to each his own.
This next option I found while perusing the ActiveRecord source and no one seems to be talking about! ActiveRecord::Relation does have #where_values_hash. This method, like #proxy_options, returns a hash of conditions that would be passed to the query.
So it would be simple assert like this:
describe ".released" do
it "returns records where #released == true" do
Presentation.released.where_values_hash.should == {:released => true}
end
end
Hooray! No database call necessary, we are testing our implementation of the scope, and we are not testing ActiveRecord implementation. I think this is a great find, let me know if you see any flaws or where it could be improved!
