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

时间:2012-02-10 05:51:27

标签: ruby-on-rails rspec factory-bot

我正在努力巩固我对rails和BDD工作流程的理解,所以我想通过创建其中一个迷你博客来开始,但是使用rspec。现在我有一个ArticlesController和Article模型,以及相关的rspec文件。文章非常简单,只有标题:字符串和内容:文本,而ArticlesController是RESTful - 虽然我手写了MCV for Article,但它基本上和我用脚手架创建它一样。

但是,当我在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

我做错了什么?我使用正确的工具吗?当我运行我的测试服务器时,New,Edit,Destroy所有工作正如我所期望的那样,所以我猜这是我对RSpec理解的问题。如果我错了,请告诉我 - 谢谢!

4 个答案:

答案 0 :(得分:55)

您忘记了.reload @articleupdate行动,您的回复最有可能执行重定向,所以

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

答案 1 :(得分:6)

当您正在进行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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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