Ruby-on-rails 如何为简单的 PUT 更新编写 RSpec 测试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9223336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to write an RSpec test for a simple PUT update?
提问by oort
I'm trying to solidify my understanding of rails and the BDD workflow, so I wanted to start small by creating one of those mini-blogs, but with rspec. Right now I have an ArticlesController and Article model, and associated rspec files. Article is very simple, has just title:string and content:text, and the ArticlesController is RESTful - although I hand wrote the MCV for Article, it's basically the same as if I used a scaffold to create it.
我试图巩固我对 rails 和 BDD 工作流程的理解,所以我想通过创建其中一个迷你博客来从小事做起,但是使用 rspec。现在我有一个 ArticlesController 和 Article 模型,以及相关的 rspec 文件。Article 很简单,只有 title:string 和 content:text,并且 ArticlesController 是 RESTful——虽然我为 Article 手工编写了 MCV,但它与我使用脚手架创建它基本相同。
However I don't really know what I'm doing when it comes to writing a test in rspec for the PUT update. I'm using Factory Girl to create the article object, and so far my code looks like:
但是,当谈到在 rspec 中为 PUT 更新编写测试时,我真的不知道我在做什么。我正在使用 Factory Girl 创建文章对象,到目前为止,我的代码如下所示:
#factories.rb
FactoryGirl.define do
factory :article do
title "a title"
content "hello world"
end
#articles_controller_spec.rb
before(:each) do
@article = Factory(:article)
end
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
response.should be_successful
end
end
However I keep getting:
但是我不断得到:
Failures:
1) ArticlesController PUT 'update/:id' allows an article to be updated
Failure/Error: response.should be_successful
expected successful? to return true, got false
What am I doing wrong? And am I using the right tools? When I run my test server, New, Edit, Destroy all work as I would expect them to, so I'm guessing this is a problem with my understanding of RSpec. Let me know if I'm wrong - thanks!
我究竟做错了什么?我是否使用了正确的工具?当我运行我的测试服务器时,New、Edit、Destroy 都按照我的预期工作,所以我猜这是我对 RSpec 理解的问题。如果我错了,请告诉我 - 谢谢!
回答by Rustam A. Gasanov
You forgot to .reloadyour @article, and on updateaction your response most likely perform redirect, so
您忘记了.reload您的@article,并且update您的响应很可能会执行重定向,因此
RSpec 2:
规范 2:
describe "PUT update/:id" do
let(:attr) do
{ :title => 'new title', :content => 'new content' }
end
before(:each) do
put :update, :id => @article.id, :article => attr
@article.reload
end
it { response.should redirect_to(@article) }
it { @article.title.should eql attr[:title] }
it { @article.content.should eql attr[:content] }
end
Rspec 3:
规格 3:
describe "PUT update/:id" do
let(:attr) do
{ :title => 'new title', :content => 'new content' }
end
before(:each) do
put :update, :id => @article.id, :article => attr
@article.reload
end
it { expect(response).to redirect_to(@article) }
it { expect(@article.title).to eql attr[:title] }
it { expect(@article.content).to eql attr[:content] }
end
回答by nmott
When you are doing a PUT :updateremember that you are editing an existing model, which you need to call in the put. Just pass your @articleand update the attributes as follows.
当您在做时,PUT :update请记住您正在编辑现有模型,您需要在put. 只需传递您的@article并更新属性,如下所示。
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
put :update, :id => @article.id, :article => @article.attributes = { :title => "new title", :content => "new content" }
response.should be_successful
end
end
回答by Sandip Ransing
FactoryGirl.define :article do
title "a title"
content "hello world"
end
before(:each) do
@article = Factory(:article)
end
it "should re-render edit template on failed update" do
@attr = { :title => "", :content => "new content" }
put :update, :id => @article.id, :article => @attr
flash[:notice].should be_nil
response.should render_template('edit')
end
it "should redirect to index with a notice on successful update" do
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
assigns[:article].should_not be_new_record
flash[:notice].should_not be_nil
response.should redirect_to(:action => 'index')
end
回答by David Hahn
The way I like to test the update method is to just ensure that the updated_at time is greater than it was before. When you do this you can change the contents of the entire instance variable and still check if everything was updated. For instance:
我喜欢测试更新方法的方式是确保updated_at 时间比以前大。当您这样做时,您可以更改整个实例变量的内容,并且仍然检查是否所有内容都已更新。例如:
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
prev_updated_at = @article.updated_at
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
@article.reload
@article.updated_at.should != prev_updated_at
end
end

