Last Updated: February 25, 2016
·
868
· ktusznio

Using Rspec's shared_examples to spec new behavior

Suppose we have a CartController and a corresponding spec. At the moment, only logged-in users can add items to their carts, and we want to support carts for guest users.

So far, the spec might look like this:

describe CartController do
  let(:user) { create(:user) }
  let(:item) { create(:item) }
  let(:response_items) { JSON.parse(response["items"]) }

  describe :index do
    it "returns items in the cart" do
      user.cart.add(item)

      get :index

      response_items[0]["id"].should == item.id
    end
  end

  describe :create do
    it "adds an item to the cart" do
      post :create, id: item.id

      response_items[0]["id"].should == item.id
    end
  end

  describe :destroy do
    it "removes an item from the cart" do
      user.cart.add(item)

      delete :destroy, id: item.id

      response_items.should be_empty
    end
  end
end

Now, to add support for guest carts, it might be tempting to add stuff like:

it "adds an item to the cart when user is a guest"
it "removes an item to the cart when user is a guest"

But that will end up repeating a lot of the previous specs. It's important to isolate what's really changing, which is the user. So, let's set up some context blocks for the two scenarios:

context "signed in user" do
  let(:user) { create(:user) }
end

context "guest user" do
  let(:user) { User.new }
end

Now, we just need our previous specs to run in these two contexts. We can do that by moving them into shared examples and running those examples in our contexts:

shared_examples "cart requests" do
  describe :index
  describe :create
  describe :destroy
end

context "signed in user" do
  let(:user) { create(:user) }

  it_behaves_like "cart requests"
end

context "guest user" do
  let(:user) { User.new }

  it_behaves_like "cart requests"
end

With this approach, we've added a whole new layer of behavior to our specs with very little repetition or actual code.

And most importantly, since we've reused the previous specs, we can be certain that all of the functionality a real user has is also available to guest users.