Rails RSpec Tests for a has_many :through Relationship
Asked Answered
S

4

35

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!!

Sarcenet answered 19/10, 2010 at 23:50 Comment(0)
I
7

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)

Incorporate answered 29/3, 2020 at 16:55 Comment(0)
K
73

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.

Karnak answered 20/10, 2010 at 0:0 Comment(4)
are there any common things you personally do when testing? I'm looking for baseline things i should do right off the bat when getting started. Things like... testing my associations seems reasonable but should i then test every method through the association? or how does one know when to stop?! lolSarcenet
I really like using these quick one-line tests because they are incredibly easy to setup. I always start with these and add every relationship and validation, including all the through associations. It doesn't take much work and doesn't add much overhead to your tests. Then as I add functionality, I will add more unit tests. If you write the tests for your models as you're writing the code, it really forces you to write simple, modular code.Karnak
how to write has_many through association with expect syntex?Angara
how you handle source in rspec. i.e if for e.g: has_many :matched_indices, through: :covariances, source: :matched_indice, dependent: :destroy How do we test this?Seraphine
I
7

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)

Incorporate answered 29/3, 2020 at 16:55 Comment(0)
F
2

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
Flatus answered 20/10, 2010 at 8:14 Comment(2)
remarkable sounds cool! Are you using it with a rails3 env ?Sarcenet
@Zaz, I've used it with Rails 2.2.3 and 2.3.9 so far. I believe it works with Rails 3 as well, but I haven't tried it.Flatus
E
2
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
Earley answered 6/7, 2011 at 4:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.