RSpec新手:"Update attributes => false"无法识别

Pla*_*Ton 4 rspec ruby-on-rails-3

刚开始使用RSpec.除了一个带有嵌套控制器的规范外,一切都很顺利.

我正在尝试确保当使用无效参数更新"评论"资源(嵌套在"帖子"下)时,它会呈现"编辑"模板.我很难让rspec识别出:update_attributes => false trigger.如果有人有任何建议,他们将非常感激.尝试过以下代码:

  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
Run Code Online (Sandbox Code Playgroud)

和控制器:

  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
Run Code Online (Sandbox Code Playgroud)

最后,错误:

 Failure/Error: response.should render_template("edit")
   expecting <"edit"> but rendering with <"">.
   Expected block to return true value.
Run Code Online (Sandbox Code Playgroud)

zet*_*tic 5

这是一个非常有趣的问题.快速解决方法是简单地替换以下块形式Comment.stub:

Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) }
Run Code Online (Sandbox Code Playgroud)

明确地说and_return:

Comment.stub(:find).with("12").\
  and_return(mock_comment(:update_attributes => false))
Run Code Online (Sandbox Code Playgroud)

至于为什么这两种形式应该产生不同的结果,这有点令人头疼.如果您使用第一个表单,您将看到模拟实际返回self而不是false调用存根方法时.这告诉我们它没有存根方法(因为它被指定为空对象).

答案是,当传入一个块时,该块仅在调用存根方法时执行,而不是在定义存根时执行.因此,当使用块形式时,以下调用:

put :update, :post_id => mock_comment.post.id, :id => "12"
Run Code Online (Sandbox Code Playgroud)

正在mock_comment第一次执行.由于:update_attributes => false未传入,因此该方法不是存根,而是返回模拟而不是false.当块调用mock_comment它返回时@mock_comment,它没有存根.

相反,使用显式形式立即and_return调用mock_comment.使用实例变量而不是每次调用方法以使意图更清晰可能更好:

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
Run Code Online (Sandbox Code Playgroud)