Rspec with inherited_resources is redirecting instead of rendering on failed update
I am new to both rspec and inherited_resources. I have a simple resource, Contact, that has a name field. The controller has no special functionality.
class ContactsController < InheritedResources::Base
actions :all, :except => [:show]
end
I have written specs for create and index just fine, using mock_model. However, when using mock_model on update, it couldn't find the contact when putting. So, I switched to using real models:
describe "PUT update" do
let(:contact) { Contact.create(:name => "test 1") }
it "edits the contact" do
contact.name = "#{contact.name}-edited"
end
context "when the contact updates successfully" do
before do
contact.stub(:save).and_return(true)
end
it "redirects to the Contacts index" do
put :update, :id => contact.id, :contact => contact
#assigns[:contact].name = "test 1 - edited"
response.should redirect_to(:action => "index")
end
end
context "when the contact fails to save" do
before do
contact.stub(:save).and_return(false)
contact.stub(:update_attributes).and_return(false)
contact.stub(:errors).and_return(:errors => { :anything => "anything" })
end
it "renders the edit template" do
put :update, :id => contact.id, :contact => contact
response.should render_template :edit
end
end
end
I get the following error:
Failures:
1) ContactsController PUT update when the contact fails to save renders the edit template
Failure/Error: response.should render_template :edit
Expected block to return true value.
# ./spec/controllers/contacts_controller_开发者_Python百科spec.rb:82:in `block (4 levels) in <top (required)>'
When I inspect the status_code, it's a 302 redirect to /contacts/:id.
What am I doing wrong?
This is a really common problem when people start using mocks in controller tests. You're stubbing methods on an object that's local to the spec. When you access your controller with put
, InheritedResources is calling Contact.find(params[:id])
and getting back its own object, not the object you want it to.
Your spec fails because update_attributes
runs without issue and redirects back to the object's show
page.
The general fix for this is to also mock the find
method on your model so that it instead returns your stubbed-out object instead of a different one.
Contact.should_receive(:find).and_return(contact)
contact.should_receive(:update_attributes).and_return(false)
put :update, :id => contact.id, # etc.
精彩评论