Shared example groups are a feature of rspec that allow specifying common behavior in a reusable group of specs.
I believe that there is a very specific way in which one can benefit from shared examples groups (and should keep them) and many more in which they come in handy at some point and should be refactored away from as development continues.
When shared examples may seem a good idea
If an application employs mechanisms such as mixins, delegation, or inheritance (which every Rails app by default does…), one can probably find some common behavior. Take a soft-delete functionality for example: specifying for each class that it’s objects are soft-deletable and that
it_behaves_like :soft_deletable seems nice, but comes at a cost (and isn’t appropriate).
Shared examples make for a slow test suite
If there are
n test cases and
m specs in the shared examples, there is a total of
n*m specs that will run. Obviously the shared example saves a lot of spec coding:
m shared specs, and
n references to it. Meaning you need to write only
If, however, it were possible to test the common functionality separately (
m specs) and then test only its integration (
n specs), there would still be
n+m specs to write, but more importantly, there would also be only
n+m specs to execute.
n+m, that’s a huge difference.
How to test common code without shared example groups
There are a couple of ways to test common code without resorting to shared examples.
In your spec, write a test harness class that gets your mixin, delegate, or (abstract) super class. This class only has the abilities of a non-special object and the common code. Testing this class allows testing the common code in an isolated way.
If you happen to be relying on ActiveRecord for your mixin as soft-deletable probably would be, use Temping to create an ActiveRecord object that only has ActiveRecord::Base behavior and that of the common code.
In case you have shared example groups in place, but can’t apply either of the above options, you probably haven’t extracted the code enough yet. Do that first and then come back here and refactor away from the shared example group.
Is a shared example group ever the right thing to do?
Imagine a mixin that has complex interactions with the objects it gets mixed in to, like a
it_behaves_like :fuzzy_matchable. Fuzzy matching will always work in a similar way, but be working on different attributes or methods depending on the object. In this case the interactions between the object and the mixin are important to specify and verify. David Chelimsky describes this situation in his post about specifying Mixins with shared example groups. This kind of complex interaction seems to me to be the only case in which shared example groups are truly beneficial.
Am I missing good use cases of shared example groups here? Where do you use them?
About the Author