For an overview, look at this StackOverflow post and then head over to the official RSpec documentation on shared examples. The best option seems to be testing concerns together with the models that include them. This post summarizes the approach I took in testing concerns on a recent project.

I followed the RSpec convention of putting the shared tests for concerns under spec/support/concerns. I need to tell RSpec to “autorequire” the spec/support folder, and the last line of my sample rails_helper.rb does just that:

# /spec/rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("Do not run in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'devise' 
...
# autorequire the spec/support
Dir["./spec/support/**/*.rb"].sort.each {|f| require f} # autorequire the files

A possible spec for the Taggable concern is:

# in spec/support/concerns/taggable.rb
require 'spec_helper'

shared_examples_for 'taggable' do
  let (:model) {create (described_class.to_s.underscore)}
  
  it 'has a name' do
    expect {model.tag_name}.to_not raise_error
  end
  
  # other tests here ...

Then, in the specs for my models that include Taggable, line 6 runs the ‘shared’ tests for the concern. For example:

1
2
3
4
5
6
7
8
9
10
# in spec/models/article_spec.rb
require 'rails_helper'

describe Article do

  it_behaves_like 'taggable'

  # model-specific tests 
  it "is valid with posted_date" 
  # ...

Lastly, a number of StackOverflow contributors have warned against “autorequiring” the spec/support folder because this will slow down tests that do not need additional files. In my experience, this is mostly true if you run individual specs frequently, but I usually run my tests together, or at least I run them in groups. For example, I would run all the model specs with rspec spec/models/.