24

I know you can easily test a belongs to relationship using Shoulda:

describe Dog dog
  it { should belong_to(:owner) }
end

Is it possible to test a more complicated belongs_to relationship using Shoulda? Something like this:

class Dog < ActiveRecord::Base
  belongs_to :owner, :class_name => "Person", :foreign_key => "person_id"
end
LandonSchropp
  • 10,084
  • 22
  • 86
  • 149

5 Answers5

27

You should be able to use:

it { should belong_to(:owner).class_name('Person') }

Shoulda's belong_to matcher always reads the foreign_key from the association and tests that it is a valid field name, so you don't need to do anything more.

(See Shoulda::Matchers::ActiveRecord::AssociationMatcher#foreign_key_exists? and associated methods)

georgebrock
  • 28,393
  • 13
  • 77
  • 72
16

Now it's possible to test custom foreign keys:

it { should belong_to(:owner).class_name('Person').with_foreign_key('person_id') }

See : https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_record/association_matcher.rb#L122

pwoestelandt
  • 161
  • 1
  • 4
4

if association like

belongs_to :custom_profile, class_name: 'User', foreign_key: :custom_user_id, optional: true

then rspec should be

it { should belong_to(:custom_profile).class_name('User').with_foreign_key('custom_user_id').optional }

here optional used for optional: true, you can also remove it if optional true not required in your association

3

So the should-matchers README is pretty light on the details, just having some examples. I found there is a lot more information in the RDoc of the classes, in the case of belongs_to take a look at association_matcher.rb. The first method is for belongs_to with the Rdoc

  # Ensure that the belongs_to relationship exists.
  #
  # Options:
  # * <tt>:class_name</tt> - tests that the association makes use of the class_name option.
  # * <tt>:validate</tt> - tests that the association makes use of the validate
  # option.
  #
  # Example:
  #   it { should belong_to(:parent) }
  #
  def belong_to(name)

So belongs_to only support tests for :class_name and :validate.

mguymon
  • 8,946
  • 2
  • 39
  • 61
3

I know I'm a bit late to the party, so my solution might require an up to date version of shoulda.

At the time of writing I'm at v 2.4.0.

I did not need class_name or with_foreign_key in my spec.

Make sure you specified class_name and foreign_key in your model.

# model.rb:  
belongs_to :owner, inverse_of: :properties, class_name: "User", foreign_key: :owner_id

# spec.rb:  
it { should belong_to(:owner) }

resulting output:

should belong to owner
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Webdevotion
  • 1,223
  • 13
  • 24