2011-06-12 45 views
19

我很努力在Rails中測試更新方法。我正在使用標準內置測試框架(test::unit)和Rails 3.0.8。我已經創建了一個用於測試的最小應用程序,但是我無法使其工作。這是我做的:如何在Rails中測試更新方法

我創建一個新的空白Rails應用程序:

rails new testapp 

創建一個模式叫收藏:

rails generate model collection name:string 

運行耙分貝:遷移:

rake db:migrate 

使用更新方法創建一個名爲Collections的控制器:

rails generate controller collections update 

在collection_controller.rb我添加此最小更新方法:

def update 
    @collection = Collection.find(params[:id]) 
    @collection.update_attributes(params[:collection]) 
end 

的測試夾具是默認值(collections.yml):

one: 
    name: MyString 

two: 
    name: MyString 

然後,添加這個到collection_controller_test。 rb下功能:

test "should update collection" do 
    put :update, :id => collections(:one), :collection => {:name => 'MyString2'} 
    assert_equal "MyString2", collections(:one).name 
end 

當我運行測試:

rake test:functionals 

它失敗,此消息:

test_should_update_collection(CollectionsControllerTest) [/Users/atle/Documents/Rails/testapp/test/functional/collections_controller_test.rb:6]: 
<"MyString2"> expected but was 
<"MyString">. 

下面是test.log中輸出:

[1m[36mSQL (0.2ms)[0m [1m SELECT name 
FROM sqlite_master 
WHERE type = 'table' AND NOT name = 'sqlite_sequence' 
[0m 
[1m[35mCollection Load (0.1ms)[0m SELECT "collections".* FROM "collections" WHERE "collections"."id" = 980190962 LIMIT 1 
Processing by CollectionsController#update as HTML 
Parameters: {"id"=>#<Collection id: 980190962, name: "MyString", created_at: "2011-06-12 13:14:13", updated_at: "2011-06-12 13:14:13">, "collection"=>{"name"=>"MyString2"}} 
[1m[36mCollection Load (0.2ms)[0m [1mSELECT "collections".* FROM "collections" WHERE "collections"."id" = 980190962 LIMIT 1[0m 
[1m[35mAREL (0.2ms)[0m UPDATE "collections" SET "name" = 'MyString2', "updated_at" = '2011-06-12 13:14:13.394135' WHERE "collections"."id" = 980190962 
Rendered collections/update.html.erb within layouts/application (1.5ms) 
Completed 200 OK in 9ms (Views: 4.5ms | ActiveRecord: 1.2ms) 

在日誌中我可以看到UPDATE聲明,但我從來沒有看到一個新的SELECT聲明。

有人可以向我解釋我做錯了嗎?

+2

對於一個明確提出的問題+1。很高興看到一位新用戶詢問這個詳細程度的明確問題。你的問題肯定來自你的斷言中的'collections(:one)',它只是從夾具中讀取數據,而不是數據庫。 Cameron和Teddy在下面都有這個正確答案。 (順便說一句:看看'factory_girl'和轉儲fixture完全儘快。他們很方便入門,但後來一個可怕的混亂。) – jdl 2011-06-12 14:20:19

+0

所以夾具和數據庫是兩個不同的位置。我假設在啓動時將fixtures讀入數據庫,並且從db讀取集合(:one)。謝謝你清理的東西,我會看看factory_girl :) – Atle 2011-06-12 15:18:19

回答

13

您正在重新加載夾具數據,而不是從數據庫中讀取數據。嘗試類似

assert_equal "MyString2", Collection.find(collections(:one)).name 

您可能需要在燈具中指定ID。

聲明:我還沒有測試過這個。

+1

這工作,現在我的測試工作,謝謝! – Atle 2011-06-12 15:05:23

+0

如果您不需要,請不要在測試中使用數據庫。你不想測試數據庫是否工作,對嗎? – schmijos 2015-07-16 12:29:52

17

您可以對HTTP響應期間創建的實例變量聲明:

test "should update collection" do 
    put :update, :id => collections(:one), :collection => {:name => 'MyString2'} 
    assert_equal "MyString2", assigns(:collection).name 
end 
+0

您的建議也奏效,但自從他第一次以來,我接受了卡梅隆的答案;)謝謝! – Atle 2011-06-12 15:07:23

+0

這是更好的答案,因爲它不使用數據庫。 – schmijos 2015-07-16 12:30:28

+0

這是正確的答案。 Collection.find(集合(:一))是醜陋的。 – hellion 2016-05-08 19:14:26

2

我的這個喜愛的變種:

test "should update collection" do 
    coll = collections(:one) 
    put :update, :id => coll, :collection => {:name => "MyString2"} 
    assert_equal "MyString2", coll.reload.name 
end 

assigns(:collection)招實際上並不保證記錄被保存了。這可能不是問題,也可能是一個驚喜。

+0

如果可能,請使用'assigns'。你不需要爲你想測試的任何數據庫交互。 – schmijos 2015-07-16 12:31:16