Skip to content
By reinteractive

Rspec- Shared Examples and Contexts

by Rodrigo Souza

The best part of choosing Rspec as your tool for automatic tests is the possibility to describe your expectations with readable text sentences. Today, We will present to you two components of Rspec that can make it even more doable.

Shared Contexts

Shared contexts is a way to always don't repeat yourself. It allows us to reuse some tests setup (let, subject, described_class, and other generalisms) for different sets of tests. Let's see the example below:

# app/models/bottle.rb
class Bottle < ApplicationRecord
  MAX_CAPACITY = 330

  def full?
    current_content >= MAX_CAPACITY
  end
end

# app/models/bowl.rb
class Bowl < ApplicationRecord
  MAX_CAPACITY = 600

  def full?
    current_content >= MAX_CAPACITY
  end
end

Let's imagine two models, Bottle and Bowl. As containers, they share a common method called full?. Let's see how we could write our tests using shared_context:

# spec/support/shared_contexts/filled.rb
RSpec.shared_context 'filled' do
  let(:current_capacity) { 50 }

  subject { described_class.new(current_capacity: current_capacity) }
end

# spec/models/bottle_spec.rb
RSpec.describe Bottle, type: :model do
  describe 'full?' do
    context 'when the bottle is' do
      context 'not full' do
        include_context 'filled'

        it 'returns false' do
          expect(subject).to be_falsey
        end
      end

      context 'is full' do
        include_context 'filled' do
          let(:current_capacity) { 330 }
        end

        it 'returns false' do
          expect(subject).to be_falsey
        end
      end
    end
  end
end

# spec/models/bowl_spec.rb
RSpec.describe Bowl, type: :model do
  describe 'filled?' do
    context 'when the bowl is' do
      context 'not full' do
        include_context 'filled'

        it 'returns false' do
          expect(subject).to be_falsey
        end
      end

      context 'is full' do
        include_context 'filled' do
          let(:current_capacity) { 600 }
        end

        it 'returns true' do
          expect(subject).to be_truthy
        end
      end
    end
  end
end

See? The tests are using the same configuration context and build different objects to run correctly. Easy and clean, no?

Perfect but, reading the specs you could say: Ok, but the tests per si seem pretty equal to me and duplicated no? I need to agree with you. The next topic will help us to improve that.

Shared examples

Shared examples allow us to reuse a bunch of tests for multiple features of our applications. Using the same example above, we could have something like this:

# spec/support/shared_examples/fillable_spec.rb
RSpec.shared_examples 'Fillable' do |received_capacity|
  describe 'full?' do
    context "when the #{described_class.downcase}" is do
      context 'not full' do
        include_context 'filled'

        it 'returns false' do
          expect(subject).to be_falsey
        end
      end

      context 'is full' do
        include_context 'filled' do
          let(:current_capacity) { received_capacity }
        end

        it 'returns true' do
          expect(subject).to be_truthy
        end
      end
    end
  end
end

# spec/models/bottle_spec.rb
RSpec.describe Bottle, type: :model do
  it_behaves_like 'Fillable', 330
end

# spec/models/bowl_spec.rb
RSpec.describe Bowl, type: :model do
  it_behaves_like 'Fillable', 600
end

Clean and tidy code so when you look at it a year from now you'll be proud.

Conclusion

Shared context and examples are great tools to DRY your code and turn it into more readable and pleasure to work with it. A good disclaimer here is about being cautious about the complexity of the abstractions when using these tools. If you need to overhide variables of the context all the time, for example, it could indicate you are going with the wrong abstraction.

Popular Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email

PLAY VIDEO PLAY VIDEO PLAY VIDEO