2010-04-20 140 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