Filtering examples in rspec-2
June 14th, 2010
In RSpec-2, every example group and example has associated metadata, to which you can append arbitrary information. This allows you to slice and dice a spec suite in a variety of ways.
Adding arbitrary metadata
The describe and it methods, and their aliases, each accept a hash as the last argument before the block:
describe "something", :this => {:is => :arbitrary} do it "does something", :and => "so is this" do # ... end end
filter_run
The keys in these hashes can be accessed in a number of ways via RSpec.configure. If, for example, you’re working on a specific example and don’t want to run the full suite, you can use the filter_run method on the configuration like this:
# in spec/spec_helper.rb RSpec.configure do |c| c.filter_run :focus => true end # in spec/any_spec.rb describe "something" do it "does something", :focus => true do # .... end end
Now if you run rspec spec, it will only run that one example, no matter how many others there are in the suite.
This works for examples and groups, so if you want to run all the examples in one group that you’re focusing on, but nothing else, you can do this:
RSpec.configure do |c| c.filter_run :focus => true end describe "something", :focus => true do it "does something" do # .... end it "does something else" do # .... end end
The rspec command would now run both of the examples in that group.
filter_run_excluding
This is the inverse of filter_run. It excludes any examples or groups that match the filter:
RSpec.configure do |c| c.filter_run_excluding :slow => true end describe "something", :slow => true do it "does something" do # .... end it "does something else" do # .... end end
The rspec command would now run all the other examples in the suite, but not these two.
NOTE: filter_run_excluding was added in beta.12, which was just released this morning.
lambda
You can filter on runtime conditions by assigning a lambda to a key. If your app is expected to behave differently in different versions of Ruby, you can use a lambda with filter_run_excluding like this:
RSpec.configure do |c| c.filter_run_excluding :ruby => lambda {|version| !(RUBY_VERSION.to_s =~ /^#{version.to_s}/) } end describe "something" do it "does something", :ruby => 1.8 do # .... end it "does something", :ruby => 1.9 do # .... end end
This example comes directly from rspec-core’s own spec_helper.rb.
RSpec passes 1.8 and 1.9 to the lambda, which accepts it as the version block argument. If the lambda returns true, the example is excluded from the run (because we’re using filter_run_excluding). Now the first example will only run if the ruby version is 1.8. Similarly, the latter example only runs under 1.9.
(no) command line support (yet)
We plan to add some sort of command line API to access these filters, but we’re not sure yet what this is going to look like. There is an open issue in github issues for rspec-core . Please feel free to review and add any comments there.


June 14th, 2010 at 3:19 pm
This is very cool. There is some overlap with using Rake to run subsets of tests, but I like this because of the granularity and because it’s easier to keep similar-but-differentiated tests close together (e.g. when two or more examples test the same thing, but under different conditions, such as your Ruby 1.8 vs 1.9 example).
June 15th, 2010 at 7:51 am
Awesome, can’t wait to use this. Command line support would be awesome-r. Thanks David.
June 15th, 2010 at 10:39 am
Any way to get at that arbitrary metadata from within config.before block?
I’m trying to do something like the following, so that I can switch Capybara drivers depending on whether a Steak scenario needs JavaScript or not:
config.after :each do Capybara.use_default_driver if options[:js] end end
So the question is, what would I need to do to get at the metadata (obviously the “options” thing I’m using above doesn’t actually exist in RSpec 2.
(Crosses fingers and hopes that formatting doesn’t get ruined when I click “Submit”…)
June 15th, 2010 at 12:20 pm
Very cool.
Is there a way to get access to all of the metadata before the run? For example, if there are any scenarios with {:filter => true}, then only run those, otherwise, run them all.
June 24th, 2010 at 1:28 pm
Brandon - YES!!!!!!!!
We actually use that in rspec-core’s own specs: http://github.com/rspec/rspec-core/blob/02dba1ab2b66adbf3b0b9424020eada48760332a/spec/spec_helper.rb#L54
June 28th, 2010 at 7:05 am
David, this focus => true feature is awesome. And this run_all_when_everything_filtered (little cryptic maybe) option is really great too. It would be even more awesome to have these configuration automatically added when launching rspec with (for example) –focus option. So users of tools like RSpactor (complete rewrite in progress!) will have access to this feature without modifying their spec_helper.rb.
What do you think about that?
June 28th, 2010 at 8:03 pm
Thibaud - please submit a feature request: http://github.com/rspec/rspec-core/issues. Thx
December 6th, 2010 at 6:37 am
@Wincent
The little snippet under RSpec & Metadata will probably answer your question.
https://github.com/cavalle/steak/blob/e044f2f2f21aa2181cd35bf0bda75d764f9d0284/README.rdoc
In the example :type being the metadata being filtered upon.
June 19th, 2012 at 9:05 am
Have you considered adding some differing opinions to the article? I think it might enhance viewers understanding.
August 20th, 2012 at 1:29 pm
I’m trying to trim the bloat on my asynchronous workers. It would be nice to filter all non-background-job related specs. But to go through each file would be a real pain.
Is there a way for me to filter specs (in the aforementioned Rspec.configure block) by path?
For example: all spec/controller/_spec.rb; spec/view/_spec.rb (though I would still want spec/view/mailer/*_spec.rb), etc
Thanks
August 20th, 2012 at 1:31 pm
For clarification on that last post: I am trimming the bloated workers by attempting to load less of Rails
it is therefore, that I’d like to also trim the specs, to ensure I haven’t trimmed too much.
August 20th, 2012 at 3:26 pm
just realized this was an old post (sorry). Also, I got my answer from here: https://github.com/rspec/rspec-core/issues/128
October 1st, 2012 at 3:55 pm
I have read several good stuff here. Definitely worth bookmarking for revisiting. I surprise how much effort you put to make such a excellent informative site.