开发者

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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜