使用Rspec测试“关联”正确的方法是什么?

50

我正在尝试测试以下场景:

-> 我有一个模型叫做Team,它只有在被用户创建后才有意义。因此,每个Team实例都必须与一个用户相关联。

为了测试这一点,我已经做了以下工作:

describe Team do

...

  it "should be associated with a user" do
    no_user_team = Team.new(:user => nil)
    no_user_team.should_not be_valid
  end

...

end

这迫使我将团队模型更改为:

class Team < ActiveRecord::Base
  # Setup accessible (or protected) attributes for your model
  attr_accessible :name, :user

  validates_presence_of :name
  validates_presence_of :user

  belongs_to :user
end

你觉得这个是否正确?我只是担心使:user属性易受访问(批量赋值)。

4个回答

69

我通常使用以下方法:

describe User do
  it "should have many teams" do
    t = User.reflect_on_association(:teams)
    expect(t.macro).to eq(:has_many)
  end
end

更好的解决方案是使用 gem shoulda,它可以让你轻松地实现以下操作:
describe Team do
  it { should belong_to(:user) }
end

1
shoulda 实际上测试了什么?我想确保当创建一个新的团队时,它实际上属于一个用户。 - Hommer Smith
Shoulda 将测试它,它将“确保belongs_to关系存在”(http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/Shoulda/Matchers/ActiveRecord#belong_to-instance_method)。因此,您可以安全地假设当您创建一个新的团队时,它将属于一个用户。 - Luís Ramalho
1
我刚刚测试了一下,发现我可以创建一个没有指定用户的团队。Shoulda 似乎只是检查模型中是否存在 belongs_to。我想确保一个团队与一个用户相关联...我相信我需要在创建团队时验证关联用户的存在。 - Hommer Smith
Hommer,我做了一些研究,似乎你必须添加validates :user, presence: true来确保外键正确设置。请查看此链接:https://dev59.com/dG435IYBdhLWcg3w2z98 - Luís Ramalho
1
现在对于任何人来说,expect(t.macro).to eq(:has_many) 是一种新的语法。 - Zoinks10

27
  it { Idea.reflect_on_association(:person).macro.should  eq(:belongs_to) }
  it { Idea.reflect_on_association(:company).macro.should eq(:belongs_to) }
  it { Idea.reflect_on_association(:votes).macro.should   eq(:has_many) }

5
我更喜欢这个解决方案而不是上面的那个。Shoulda 宝石破坏了我所有的 Pundit 测试,虽然有方法可以解决,但我宁愿避免使用这个似乎有缺陷的宝石。 - ian root
2
这适用于Rails 5.0.1,rspec 3.5.0和rspec-rails 3.5.2。 - Charlie

1
class MicroProxy < ActiveRecord::Base
    has_many :servers
end

describe MicroProxy, type: :model do
    it { expect(described_class.reflect_on_association(:servers).macro).to eq(:has_many) }
end

urbanczykd的答案的副本 - Vasilisa
1
@Vasilisa 当前Rspec版本的社区惯例鼓励使用expect而不是should。http://www.betterspecs.org/#expect 此外,在测试相同类时,described_class方法可用于维护性,以避免将测试与类名称锁定。https://blog.eq8.eu/article/expresive-tests-rspec.html#describing-intention - juliangonzalez
1
我同意,但你在答案中没有提到这一点。请把你的解释从评论移动到答案中。 - Vasilisa

1

RSpec是一个Ruby测试框架,而不是Rails框架。 belongs_to是Rails的构造,而不是Ruby的构造。 像shoulda-matchers这样的Gem连接了Ruby和Rails的东西,并帮助您编写良好的测试。

牢记以上内容并遵循官方文档应该有助于您保持最新并理解您所编写的内容。

因此,以下是我要写的内容。

用户模型:

RSpec.describe User, type: :model do
  context 'associations' do
    it { should have_many(:teams).class_name('Team') }
  end
end

团队模型:

RSpec.describe Team, type: :model do
  context 'associations' do
    it { should belong_to(:user).class_name('User') }
  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接