2010-04-20 76 views
17

我正在學習如何使用Rspec編寫測試用例。我有一個簡單的帖子評論腳手架,其中帖子可以有很多評論。我正在測試這個使用Rspec。我應該如何去檢查Post :has_many :comments。我應該存根Post.comments方法,然後通過返回評論對象數組的模擬對象來檢查此方法嗎?是否真的需要測試AR協會?檢查RSpec中的ActiveRecord關聯

回答

28

由於ActiveRecord關聯應該經過Rails測試套件(以及它們)的充分測試,大多數人並不認爲需要確保它們正常工作 - 只是假定它們會。

如果你想確保你的模型是使用這些關聯,這是不同的,你想要測試它沒有錯。我喜歡使用shoulda寶石來做到這一點。它可以讓你做巧妙的事情是這樣的:

describe Post do 
    it { should have_many(:comments).dependent(:destroy) } 
end 
+0

謝謝!現在有一個相當清晰的看法。 – 2010-04-20 07:34:35

+0

Woops,仔細檢查一下。我的意思是應該是寶石,而不是factory_girl。 – 2010-04-20 07:40:36

0

大多數人不測試關聯,因爲Rails已經有單元測試來確保這些方法正常工作。如果你正在做一些複雜的事情,比如涉及一個proc或者某個東西,你可能需要明確地測試它。通常你可以這樣做只是做

a = Post.new 
a.comments << Comment.new 
assert a.save 
assert a.comments.size == 1 

或類似的東西。

+0

我給你一部分。我是測試新手。假設我編寫了一個單元測試,以確認在刪除相關帖子時刪除了所有評論。這足夠了嗎?此外,我甚至需要編寫單元測試來驗證由腳手架產生的銷燬方法。 – 2010-04-20 06:48:15

12

測試協會是很好的做法普遍,特別是在TDD高度regarded-其他開發商會經常看你的規格看相應的代碼之前的環境。測試關聯確保您的spec文件最準確地反映您的代碼。

兩種方法可以測試協會:

  1. 隨着FactoryGirl:

    expect { FactoryGirl.create(:post).comments }.to_not raise_error 
    

    這是一個比較膚淺的測試將同一個工廠,如:

    factory :post do 
        title { "Top 10 Reasons why Antelope are Nosy Creatures" } 
    end 
    

    回報如果你的模型缺少與評論相關的has_many關聯,那麼你是一個NoMethodError。

  2. 您可以使用ActiveRecord #reflect_on_association方法更深入地瞭解您的關聯。舉例來說,具有更復雜的關聯:

    class Post 
        has_many :comments, through: :user_comments, source: :commentary 
    end 
    

    你可以更深入地瞭解您的關聯關係:

    reflection = Post.reflect_on_association(:comment) 
    reflection.macro.should eq :has_many 
    reflection.options[:through].should eq :user_comments 
    reflection.options[:source].should eq :commentary 
    

    和測試上的任何選項或條件有關。

1

如果你不想使用外部的寶石像shoulda測試你的協會(見Robert SpeicherAnswer用於對細節),另一種選擇是使用reflect_on_association得到AssociationReflection對象相關的關聯,然後斷言上:

describe Post do 
    it "should destroy its comments when it is destroyed" do 
    association = Post.reflect_on_association(:comments) 

    expect(association).to_not be_nil 
    expect(association.options[:dependent]).to eq :destroy 
    end 
end