I am toying with a different style of writing my rspec controller tests for a rails application based on ideas taken from this blog post on rspec best practices, and stumbled into a situation where I can't understand -- based on the order of execution of the before blocks -- how the inner-most specify block passes. It's a relatively simple test:
context "when hitting the approval queue" do
before { get :approval_queue }
subject { response }
specify { assigns(:users).should == [] }
it { should be_success }
context "when there are unapproved users" do
before { @users = (1..3).map {Factory(:user, :activated_at => nil)} }
specify { assigns(:users).should == @users }
it { should be_success }
end
end
As you can see, the outer context's before block calls the approval_queue method on a rails controller. The first couple assertions are for the situation where there are no unapproved users. Those pass as expected.
Then I nest a context with another before block which sets up 3 unapproved users (in my case unapproved users have a nil activated_at attribute). The next assertion is that the controller method assigns those 3 users to the users variable for the view. Note that I had actually called get :approval_queue BEFORE setting up the users, yet still the test passes. Totally weird! Not at all what I expected.
Ahhh, writing out this post I was able to realize what was going on. In my controller I do little more than assign @users = User.inactive . As it turns out this collection is lazily-loaded so the actual query only occurs once you start doing things with that variable. So the inner context, as written, is really a bad test... it does not do what I think it's doing. It can be tripped up by the controller being changed to operate on the @users variable... dastardly!
Having played around with this style, I'm now thinking that it does not work very well for controller tests -- though for models it could be quite useful. I definitely learned to be wary of gotchas involving lazy loading ActiveRecord stuff (damn you, rails magic! *grin*)
Error: too much magic!
Posted by: Ian | 2010.11.22 at 23:22