2012-02-10 46 views
26

我試圖鞏固我對rails和BDD工作流程的理解,所以我想通過創建這些迷你博客中的一個來開始小型項目,但是使用rspec。現在我有一個ArticlesController和Article模型,和相關的rspec文件。文章非常簡單,只有title:string和content:text,ArticlesController是RESTful - 雖然我手寫了MCV for Article,但它基本上與我使用腳手架創建它相同。如何爲簡單的PUT更新編寫RSpec測試?

然而,我並不真正知道自己在做什麼,因爲在rspec中爲PUT更新編寫測試。我使用工廠女孩以創建該項目的對象,到目前爲止,我的代碼如下所示:

#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的理解問題。讓我知道如果我錯了 - 謝謝!

+0

您的控制器和模型是什麼樣的? – 2012-02-10 05:54:23

回答

51

你忘了.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 
+0

此外,新的匹配器語法會將其作爲@ article.title.should eq @attr [:title] – engineerDave 2013-05-17 17:51:05

+1

祝福你美麗的小靈魂。我在我的智慧結束。 – Matt 2014-02-24 15:50:20

+3

較新的語法應該是:'expect(@ article.title).to eq @attr [:title]'。 – Nick 2014-07-09 18:43:07

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 
+0

是否可以使用POST進行更新? – KnownColor 2014-01-17 08:58:41

+1

默認情況下,@KnownColor更新是放置請求,但您始終可以覆蓋它。 – 2014-01-19 17:55:56

5

當你正在做一個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 
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 
+0

你的代碼似乎斷言時代是一樣的,沒有不同,如你所描述的。 – KnownColor 2014-01-17 08:58:06