Mario Zigliotto
Mario Zigliotto

Reputation: 9025

Rails RSpec Tests for a has_many :through Relationship

I'm new to testing and rails but i'm trying to get my TDD process down properly.

I was wondering if you use any sort of paradigm for testing has_many :through relationships? (or just has_many in general i suppose).

For example, i find that in my model specs i'm definitely writing simple tests to check both ends of a relationship for relating methods.

ie:

require 'spec_helper'

describe Post do

  before(:each) do
    @attr = { :subject => "f00 Post Subject", :content => "8ar Post Body Content" }
  end

  describe "validations" do
  ...    
  end

  describe "categorized posts" do

    before(:each) do
      @post  = Post.create!(@attr)
    end

    it "should have a categories method" do
      @post.should respond_to(:categories)
    end

  end

end

Then in my categories spec i do the inverse test and check for @category.posts

What else am i missing? thanks!!

Upvotes: 35

Views: 34779

Answers (4)

randmin
randmin

Reputation: 948

For the sake of completeness, in 2020 this is possible without additional gems.

  it "has many categories" do
    should respond_to(:categories)
  end

And even more explicit:

it "belongs to category" do
  t = Post.reflect_on_association(:category)
  expect(t.macro).to eq(:belongs_to)
end

(see Ruby API on Reflection)

The second example makes sure that a "has_one" is not confused with a "belongs_to" and vice versa

It is, however, not limited to has_many :through relationships, but can be used for any association applied to the model.

(Note: This is using the new rspec 2.11 syntax with Rails 5.2.4)

Upvotes: 7

Peter Brown
Peter Brown

Reputation: 51717

I would recommend checking out a gem called Shoulda. It has a lot of macros for testing things like relationships and validations.

If all you want is to test that the has_many relationship exists, then you could do the following:

describe Post do
  it { should have_many(:categories) }
end

Or if you're testing a has_many :through, then you'd use this:

describe Post do
  it { should have_many(:categories).through(:other_model) }
end

I find the Shoulda Rdoc page very helpful too.

Upvotes: 73

GregC
GregC

Reputation: 8007

describe "when Book.new is called" do
  before(:each) do
    @book = Book.new
  end

  #otm
  it "should be ok with an associated publisher" do
    @book.publisher = Publisher.new
    @book.should have(:no).errors_on(:publisher)
  end

  it "should have an associated publisher" do
    @book.should have_at_least(1).error_on(:publisher)
  end

  #mtm
  it "should be ok with at least one associated author" do
    @book.authors.build
    @book.should have(:no).errors_on(:authors)
  end

  it "should have at least one associated author" do
    @book.should have_at_least(1).error_on(:authors)
  end

end

Upvotes: 2

Wayne Conrad
Wayne Conrad

Reputation: 108159

remarkable will do this nicely:

describe Pricing do

  should_have_many :accounts, :through => :account_pricings
  should_have_many :account_pricings
  should_have_many :job_profiles, :through => :job_profile_pricings
  should_have_many :job_profile_pricings

end

Generally, you just copy all of your relationships from the model to the spec and change "has" to "should_have", "belongs_to" to "should_belong_to", and so on. To answer the charge that it's testing rails, it checks the database also, making sure that the association works.

Macros are also included for checking validations as well:

should_validate_numericality_of :amount, :greater_than_or_equal_to => 0

Upvotes: 2

Related Questions