rspec is mocking me
Grr. I hate situations where it works here, but doesn’t work there, and I can’t see where the difference is. Something has to be different, I just can’t for the life of me figure out what. Maybe someone can help.
Here’s what’s up.
I’ve got rspec and rspec-rails installed as git submodules. Running the latest edge rails. I’m gonna generate up a quick rspec_scaffold:
$ script/generate rspec_scaffold Bike name:string sku:string
This generates the following controller test (abridged):
describe BikesController do
def mock_bike(stubs={})
@mock_bike ||= mock_model(Bike, stubs)
end
describe "responding to GET index" do
it "should expose all bikes as @bikes" do
Bike.should_receive(:find).with(:all).and_return([mock_bike])
get :index
assigns[:bikes].should == [mock_bike]
end
end
end
Looks fine. BUT. In my project, this spec fails, because it is somehow loading up the view and the name and sku calls are tripping up the mock, as it isn’t expecting them to be called in this controller test.
Note, however, that I am NOT calling integrate_views inside my controller spec, so I don’t have any idea why the view code is being run.
% rake spec:controllers (snip) ActionView::TemplateError in 'BikesController responding to GET index should expose all bikes as @bikes' Mock 'Bike_1017' received unexpected message :name with (no args) On line #11 of app/views/index.html.erb 8: 9: <% for bike in @bikes %> 10: <tr> 11: <td><%=h bike.name %></td> 12: <td><%=h bike.model %></td> 13: <td><%= link_to 'Show', bike %></td> 14: <td><%= link_to 'Edit', edit_bike_path(bike) %></td> app/views/bikes/index.html.erb:11 app/views/bikes/index.html.erb:9:in `each' app/views/bikes/index.html.erb:9
This happens for 10 of the 18 scaffolded specs.
I can fix the errors by adding expectations to the mock like so:
it "should expose all bikes as @bikes" do
Bike.should_receive(:find).with(:all).and_return([mock_bike])
mock_bike.should_receive(:name)
mock_bike.should_receive(:sku)
get :index
assigns[:bikes].should == [mock_bike]
end
But that kind of defeats the purpose of having a controller-only test, as it’s now testing the view code as well.
What’s weird is, I started a brand new project, and all the tests passed with flying colors!
% rails rspectest % cd rspectest % rake db:create:all % script/plugin install git://github.com/dchelimsky/rspec.git % script/plugin install git://github.com/dchelimsky/rspec-rails.git % script/generate rspec % script/generate rspec_scaffold Bike name:string sku:string % rake db:migrate % rake spec (in /Users/john/src/test/rspectest) ..................................... Finished in 1.006109 seconds 37 examples, 0 failures
So a brand new project runs the rspec_scaffold specs in isolation, but my project somehow doesn’t.
I’m tearing my hair out on this one. I can’t figure out what I’ve done to my project to cause these specs to stop working.
Anyone out there have any ideas/suggestions?
Update!
Wow. Through the magic of git bisect, I’ve determined that the problem occurs because of a change in edge rails. Turns out, this commit causes the specs to fail. Everything before it passes, everything after fails.
I have no idea how to fix this (or if it is rails’ or rspec’s fault), but I’m getting closer. :-)
PS, if you’ve never used git bisect before, you really haven’t lived.
Update 2!
The latest commits to rspec and rspec-rails fix the problem. Bravo rspec team.