刚开始使用RSpec。除了一个带有嵌套控制器的规范外,一切都很顺利。
我正在努力确保在使用无效参数更新'comment'资源(嵌套在'post'下)时,它会呈现'edit'模板。我很难让rspec认识到:update_attributes =>误触发。如果有人有任何建议,他们将非常感激。尝试下面的代码:
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.
答案 0 :(得分: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))
至于为什么这两种形式会产生不同的结果,这有点令人头疼。如果您使用第一个表单,则会在调用stubbed方法时看到模拟实际返回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