如何为简单的 PUT 更新编写 RSpec 测试?

发布于 2025-01-04 23:23:29 字数 1110 浏览 1 评论 0原文

我正在努力巩固我对 Rails 和 BDD 工作流程的理解,因此我想通过创建这些迷你博客之一从小事做起,但使用 rspec。现在我有一个 ArticlesController 和 Article 模型,以及关联的 rspec 文件。 Article 非常简单,只有 title:string 和 content:text,ArticlesController 是 RESTful - 虽然我手写了 Article 的 MCV,但它基本上与我使用脚手架创建它一样。

然而,我真的不知道在 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

但是我不断收到:

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

我做错了什么?我使用的工具正确吗?当我运行我的测试服务器时,新建、编辑、销毁所有工作都按照我的预期进行,所以我猜测这是我对 RSpec 的理解存在问题。如果我错了请告诉我 - 谢谢!

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.

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:

#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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

各自安好 2025-01-11 23:23:29

您忘记.reload您的@article,并且在update操作时您的响应很可能会执行重定向,因此

RSpec 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:

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

You forgot to .reload your @article, and on update action your response most likely perform redirect, so

RSpec 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:

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
杀お生予夺 2025-01-11 23:23:29

当您执行 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

When you are doing a PUT :update remember that you are editing an existing model, which you need to call in the put. Just pass your @article and update the attributes as follows.

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
不如归去 2025-01-11 23:23:29
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
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
心清如水 2025-01-11 23:23:29

我喜欢测试 update 方法的方法是确保 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

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:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文