Skipping Shared Examples In RSpec

The other day as I was getting ready to deploy some code I had been working on, I noticed a pesky non-deterministic spec (a test that passes sometimes but fails other times) in our test suite. Since such specs compromise the integrity of the test suite as a whole, I wanted to skip the spec until we had the opportunity to give it the attention it deserved.

The Problem

A seemingly simple task turned into a bit of a struggle as the offending spec was a shared example, and I needed to figure out how to isolate and skip one example without affecting the other unit tests that also relied upon the shared example. I figured it might be useful to document the solution in blog form for folks who may run into a similar bump in the road.

A Theoretical Scenario

I like animals so, let’s say we have a few classes as such…

module FerociousRoar
  def roar_ferociously
    "ROOOOOOOOOOOOOOOOOOOAAAAAAAAAAAAAAAAARRRRRRRRRRRRRRRRRRRRR!"
  end
end

class Bear
  include FerociousRoar
end

class Dinosaur
  include FerociousRoar
end

I think we can all agree that bears and dinosaurs both have pretty ferocious roars, so I have included the FerociousRoar module in both animals to give them that shared behavior.

If we were to write some unit tests for these classes, they might look something like this:

shared_examples_for "it has a ferocious roar" do
  describe "#roar_ferociously" do
    it "returns a string representation of a ferocious roar" do
      expect(described_class.new.roar_ferociously)
        .to eq "ROOOOOOOOOOOOOOOOOOOAAAAAAAAAAAAAAAAARRRRRRRRRRRRRRRRRRRRR!"
    end
  end
end

describe Bear do
  it_behaves_like "it has a ferocious roar"
end

describe Dinosaur do
  it_behaves_like "it has a ferocious roar"
end

Because roaring ferociously is something that both bears and dinosaurs do, we can use a shared example to spec out this behavior for both animal classes to keep our code DRY. However, what if we need our test suite to run the shared example for our Bear specs, but skip over this shared example for our Dinosaur specs?

The Solution

The solution is really quite simple. We can pass an optional argument to our shared example, allowing us to skip a particular spec if necessary while leaving the others intact. Our shared example should now look like this:

  shared_examples_for "it has a ferocious roar" do |*flags| #Optional argument
    before { skip } if flags.include?(:skip) #Skip the example if the :skip flag is present

    it "returns a string representation of a ferocious roar" do
      expect(described_class.new.roar_ferociously).to
        eq "ROOOOOOOOOOOOOOOOOOOAAAAAAAAAAAAAAAAARRRRRRRRRRRRRRRRRRRRR!"
    end
  end

We can then update our Dinosaur specs to skip the shared example for now:

describe Dinosaur do
  it_behaves_like "it has a ferocious roar", :skip #We want to skip this shared example!
end

Meanwhile, our Bear specs will continue to run the shared example.

Shared example skipped successfully Success!

Tweet at Laura

Share this post!