Roberto Pezzali
Roberto Pezzali

Reputation: 2504

Rspec, test presence of an association

I'm trying to test an association.

I have these two classes:

class Survey < ActiveRecord::Base
  has_many :users, through: :users_surveys
  has_many :users_surveys

  def update_or_create_result(user_id, result, target)
    user_survey = users_surveys.find_or_create_by(user_id: params[:user_id])
    if survey_passed?(result, target)
      user_survey.completed!
    end
  end
end

class User < ActiveRecord::Base
  has_many :surveys, through: :users_surveys
  has_many :users_surveys
end

class UsersSurvey < ActiveRecord::Base
  belongs_to :user
  belongs_to :survey
end

How can I test with RSpec if the association between survey and user is created?

Upvotes: 6

Views: 7738

Answers (4)

max
max

Reputation: 102398

The shoulda-matchers gem provides some nifty matchers that test the association is declared and that the correct database fields and foreign keys exist:

describe User do
  it { should have_many(:surveys) }
end

If you for some reason have gem-o-phobia and just want to test it straight off the bat you can use ActiveRecord::Reflection to get information about the relations of a model:

describe User do
  it "should have_many :surveys" do
    expect(User.reflect_on_association(:surveys).macro).to eq :has_many
  end
end

describe Survey do
  it "should belong_to user" do
    expect(Survey.reflect_on_association(:user).macro).to eq :belongs_to
    expect(Survey.column_names).to include :user_id
  end
end

You can also test the behavior of your models by creating an associated object - however if you have validation requirements than your specs sometimes end up somewhat muddled since your spec for A needs to fullfil the requirements for B.

Upvotes: 3

Marek Lipka
Marek Lipka

Reputation: 51191

Assuming you have user and survey variables, it's as simple as this:

user.surveys.should include(survey)

Since your question is a bit unclear, my answer checks if association between actual two records is created.

Upvotes: 2

Andrey Deineko
Andrey Deineko

Reputation: 52377

Just want to emphasize, that current nex syntax for RSpec is the following:

describe User do
  it { is_expected.to have_many(:surveys) } # shortcut for expect(subject).to
end

describe Survey do
  it { is_expected.to belong_to(:user) }
end

should is considered to be old syntax for quite a few years now :)

Upvotes: 5

Mihai Dinculescu
Mihai Dinculescu

Reputation: 20033

If you are using or want to use Shoulda, this is straightforward

describe User do
  it { should have_many(:surveys) }
end

describe Survey do
  it { should belong_to(:user) }
end

Or, if you're testing a has_many :through, like it seems to be your case, use

describe User do
  it { should have_many(:surveys).through(:user_survey) }
end

If you do not want to use Shoulda, you need to get a little creative

describe User do
  let(:user) { User.new }

  it "should define the association" do
    expect(user).to have(:no).errors_on(:surveys)
  end
end

describe Survey do
  let(:user) { User.new }
  let(:survey) { user.surveys.create }

  it "should define the association" do
    expect(survey).to have(:no).errors_on(:user)
  end
end

Upvotes: 1

Related Questions