2011-01-14 34 views
4

刚开始使用RSpec。除了嵌套控制器的一个规格外,一切都很顺利。RSpec新手:“更新属性=> false”未被识别

我试图确保当'comment'资源(嵌套在'post'下)用无效参数更新时,它会呈现'edit'模板。我努力让rspec识别:update_attributes => false触发器。如果有人有任何建议,他们会非常感激。尝试下面的代码:

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 

而且控制器:

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 

最后,错误:

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

回答

5

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

Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) } 

有一个明确的and_return

Comment.stub(:find).with("12").\ 
    and_return(mock_comment(:update_attributes => false)) 

至于为什么这两种形式应该产生不同的结果,这是一个有点头戴式的不求人。如果你玩弄第一种形式,你会看到当调用存根方法时,模拟实际上返回self而不是false。这就告诉我们它没有存储该方法(因为它被指定为空对象)。

答案是,当传入一个块时,块只在调用存根方法时执行,而不是在存根被定义时执行。因此,使用该块的形式时,下面的呼叫:

put :update, :post_id => mock_comment.post.id, :id => "12" 

正在执行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 
+0

出色的,彻底的,明确的响应。非常感谢。 :-) – PlankTon 2011-01-14 21:47:23