0
votes

I have never written a test of my own before and I just finished my model association and migrated them, so now I wanted to test them out. I have added to gemfile and installed gem 'shoulda-matchers', '~> 3.0' under group :test, and gem 'rspec-rails', '~> 3.0' under group :development, :test. Added the configurations for shoulda-matchers into spec/rails_helper.rb. What's next? What directory will a test file go into? What are the syntactic rules for writing a shoulda matcher, same as for rspec? How can I for example check that this association works properly?

class Artist < ApplicationRecord
  has_many events, :through => :lineups
end

like this?

describe Artist do
  it { should have_many(:events).through(:lineups) }
end
1

1 Answers

2
votes

It looks good to me - here is a further example taking a class Listing that tests both the associations and validations.

class Listing < ActiveRecord::Base

  #Associations
  belongs_to :user
  belongs_to :category, inverse_of: :listings
  has_many :photos, dependent: :destroy 
  has_many :watches
  has_many :watchers, -> { uniq }, :through => :watches
  has_many :offers, dependent: :destroy
  has_many :feedbacks
  belongs_to :location, :dependent => :destroy

  # Association validations
  validates_presence_of :category
  validates_presence_of :user

  # Attribute validations
  validates_presence_of :title, message: "Please add a title."
  validates_presence_of :subtitle, message: "Please add a subtitle."
  validates_presence_of :price, message: "Please add a price."
  validates_presence_of :title, message: "Please select a condition."

require 'rails_helper'

RSpec.describe Listing, type: :model do

  #Associations
  it { should belong_to(:user) }
  it { should belong_to(:category) }
  it { should have_many(:photos) }
  it { should have_many(:watches) }
  it { should have_many(:watchers).through(:watches) }
  it { should have_many(:offers) }
  it { should belong_to(:location).dependent(:destroy) }

  #Association validations
  it { should validate_presence_of(:category) }
  it { should validate_presence_of(:user) }

  #Attribute validations
  it { should validate_presence_of(:title).with_message("Please add a title.") }
  it { should validate_presence_of(:subtitle).with_message("Please add a subtitle.") }
  it { should validate_presence_of(:price).with_message("Please add a price.") }
  it { should validate_presence_of(:title).with_message("Please select a condition.") }

Note the use of RSpec.describe Class, type: :model to specify the type of tests.

I would read the Shoulda readme that explains more about the availability of matchers in various example groups. They provide four categories of matchers:

ActiveRecord and ActiveModel matchers are available only in model example groups, i.e., those tagged with type: :model or in files located under spec/models.

ActionController matchers are available only in controller example groups, i.e., those tagged with type: :controller or in files located under spec/controllers.

The route matcher is available also in routing example groups, i.e., those tagged with type: :routing or in files located under spec/routing.

Independent matchers are available in all example groups.


In terms of arranging your specs aim to mirror your app directory (more or less).

So if you have:

app/models/user.rb
app/services/
app/controllers/
app/presenters/

You can mirror this with:

spec/models/user_spec.rb
spec/services/
spec/controllers/
spec/presenters/

You may then have some additional spec folders such as:

spec/features/ (a folder for integration/feature specs)

The RSpec documentation has some very good info on this.