RSpec Novice: "Update attributes => false" not recognized
Just start with RSpec. Everything runs smoothly, with the exception of one specification with embedded controllers.
I am trying to ensure that when the comment resource (nested under the "post") is updated with invalid parameters, it displays the "edit" template. I am trying to get rspec to recognize: update_attributes => a false trigger. If anyone has any suggestions, they will be very grateful. Trying the code below:
def mock_comment(stubs={}) stubs[:post] = return_post stubs[:user] = return_user @mock_comment ||= mock_model(Comment, stubs).as_null_object end describe "with invalid paramters" dog it "re-renders the 'edit' template" do Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) } put :update, :post_id => mock_comment.post.id, :id => "12" response.should render_template("edit") end end And the controller:
def update @comment = Comment.find(params[:id]) respond_to do |format| if @comment.update_attributes(params[:comment]) flash[:notice] = 'Post successfully updated' format.html { redirect_to(@comment.post) } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @comment.errors, :status => :unprocessable_entity } end end end And finally, the error:
Failure/Error: response.should render_template("edit") expecting <"edit"> but rendering with <"">. Expected block to return true value. This is a rather interesting problem. A quick fix is ββto simply replace the Comment.stub block Comment.stub :
Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) } with explicit and_return :
Comment.stub(:find).with("12").\ and_return(mock_comment(:update_attributes => false)) As for why these two forms should give different results, this is a bit of head-scratching. If you play with the first form, you will see that the layout actually returns self instead of false when calling the stubbed method. This suggests that he did not stop the method (since it is listed as a null object).
The answer is that when transferring in a block, a block is executed only when the stubbed method is called, and not when a stub is defined. Therefore, using the form of the block, the following call is called:
put :update, :post_id => mock_comment.post.id, :id => "12" performs mock_comment for the first time. Since :update_attributes => false not passed, the method does not fade, and the mock is returned, not false . When a block calls mock_comment , it returns @mock_comment , which does not have a stub.
Contrariwise, using the explicit and_return view, immediately calls mock_comment . It is probably best to use an instance variable instead of calling a method each time to make the intent more clear:
it "re-renders the 'edit' template" do mock_comment(:update_attributes => false) Comment.stub(:find).with("12") { @mock_comment } put :update, :post_id => @mock_comment.post.id, :id => "12" response.should render_template("edit") end