50

I am trying to test the following scenario:

-> I have a model called Team which it just makes sense when it has been created by a User. Therefore, each Team instance has to be related to a User.

In order to test that, I have done the following:

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

Which forces me to change the Team model as:

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

Does this seem correct to you? I am just worried of make the :user attribute as accessible (mass assignment).

Hommer Smith
  • 26,772
  • 56
  • 167
  • 296

4 Answers4

69

I usually use this approach:

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

A better solution would be to use the gem shoulda which will allow you to simply:

describe Team do
  it { should belong_to(:user) }
end
Bijan
  • 25,559
  • 8
  • 79
  • 71
Luís Ramalho
  • 10,018
  • 4
  • 52
  • 67
  • 1
    What does shoulda actually tests? I want to ensure that when a new Team is created it actually belongs to a user. – Hommer Smith Mar 30 '13 at 22:00
  • `Shoulda` will test that, it will "ensure that the belongs_to relationship exists" (http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/Shoulda/Matchers/ActiveRecord#belong_to-instance_method). Thus, you can safely assume that when you create a new Team it will belong to a user. – Luís Ramalho Mar 30 '13 at 22:02
  • 1
    I just tested that and I am able to do create a Team without specifying a User. Shoulda seems to just check if belongs_to exist in the model. I want to be sure that a Team has a User associated with it...I believe I need to validate that there is a presence of the associated User when creating a Team... – Hommer Smith Mar 30 '13 at 22:04
  • Hommer, I've done some research and it seems that you must add `validates :user, presence: true`in order to ensure that the foreign keys is properly set up. Check this http://stackoverflow.com/questions/5176510/validates-associated-not-checking-existence-of-associations – Luís Ramalho Mar 30 '13 at 22:17
  • 1
    New syntax for anyone these days is `expect(t.macro).to eq(:has_many)`. – Zoinks10 Jan 16 '16 at 03:45
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) }
urbanczykd
  • 319
  • 3
  • 4
  • 5
    i prefer this solution over the one above it. the shoulda gem broke all my pundit tests, and while there are workarounds, i'd rather just avoid using what appears to be a buggy gem. – ian root Dec 08 '15 at 00:28
  • 2
    This works with Rails 5.0.1, rspec 3.5.0, and rspec-rails 3.5.2. – Charlie Jan 26 '17 at 16:39
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
juliangonzalez
  • 4,231
  • 2
  • 37
  • 47
  • Duplicate of urbanczykd's answer – Vasilisa Jul 17 '19 at 03:40
  • 1
    @Vasilisa the community convention for current Rspec version encourages the use of `expect` instead of `should` http://www.betterspecs.org/#expect Also when testing the same class `described_class` method is available for the maintaniabilty purpose of not locking the test with the class name https://blog.eq8.eu/article/expresive-tests-rspec.html#describing-intention – juliangonzalez Jul 17 '19 at 18:12
  • 1
    I agree, but you said nothing about it in the answer. Please, move your explanation from the comment to the answer – Vasilisa Jul 18 '19 at 03:00
1

RSpec is a ruby test framework, and not a rails framework. belongs_to is a rails construct, and not a ruby construct. Gems like shoulda-matchers connect ruby and rails things and help you write good tests.

Having the above in mind and following official documentation, should help you stay up to date and understand what you are writing.

So, below is what I would write.

User model:

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

Team model:

RSpec.describe Team, type: :model do
  context 'associations' do
    it { should belong_to(:user).class_name('User') }
  end
end
Abeyance
  • 133
  • 1
  • 2
  • 7