In the examples in this chapter, we’ve always run all the specs together. On a real project, you don’t necessarily want to load your entire test suite every time you invoke RSpec.
If you’re diagnosing a specific failure, for instance, you’ll want to run just that one example. If you’re trying to get rapid feedback on your design, you can bypass slow or unrelated specs.
The easiest way to narrow down your test run is to pass a list of file or directory names to rspec:
| $ rspec spec/unit # Load *_spec.rb in this dir and subdirs |
| $ rspec spec/unit/specific_spec.rb # Load just one spec file |
| $ rspec spec/unit spec/smoke # Load more than one directory |
| $ rspec spec/unit spec/foo_spec.rb # Or mix and match files and directories |
Not only can you load specific files or directories, you can also filter which of the loaded examples RSpec will actually run. Here, we’ll explore a few different ways to run specific examples.
Rather than running all the loaded specs, you can choose a specific example by name, using the --example or -e option plus a search term:
| $ rspec -e milk -fd |
| Run options: include {:full_description=>/milk/} |
| |
| A cup of coffee |
| with milk |
| costs $1.25 (FAILED - 1) |
| |
| Failures: |
| |
| 1) A cup of coffee with milk costs $1.25 |
| Failure/Error: expect(coffee.price).to eq(1.25) |
| |
| expected: 1.25 |
| got: 1.0 |
| |
| (compared using ==) |
| # ./spec/coffee_spec.rb:26:in ‘block (3 levels) in <top (required)>’ |
| |
| Finished in 0.01014 seconds (files took 0.08249 seconds to load) |
| 1 example, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:25 # A cup of coffee with milk costs $1.25 |
RSpec ran just the examples containing the word milk (in this case, just one example). When you use this option, RSpec searches the full description of each example; for instance, A cup of coffee with milk costs $1.25. These searches are case-sensitive.
Often, what you really want to do is run just the most recent failing spec. RSpec gives us a handy shortcut here. If you pass a filename and line number separated by a colon, RSpec will run the example that starts on that line.
You don’t even have to manually type in which file and line to rerun. Take a look at the end of the spec output:
| $ rspec |
| .F |
| |
| truncated |
| |
| 2 examples, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:25 # A cup of coffee with milk costs $1.25 |
You can copy and paste the first part of that final line (before the hash) into your terminal to run just the failing spec. Let’s do so now:
| $ rspec ./spec/coffee_spec.rb:25 |
| Run options: include {:locations=>{"./spec/coffee_spec.rb"=>[25]}} |
| F |
| |
| truncated |
| |
| 1 example, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:25 # A cup of coffee with milk costs $1.25 |
RSpec ran only the single example you specified. This focusing ability becomes even more powerful when you add a key binding for it to your text editor. Several IDEs and editor plugins provide this behavior for you, including the following:
With good editor support, you can quickly run the example under your cursor with a single keystroke.
Use Editor Integration for a More Productive Experience | |
---|---|
![]() |
Having to switch back and forth between your editor and a terminal window in order to run rspec really interrupts your workflow. We recommend taking the time to install an editor plugin so that running rspec is only a keystroke away. |
Using a line number works well when only one spec is failing. If you have more than one failure, you can run all of them with the --only-failures flag. This flag requires a little bit of configuration, but RSpec will coach you through the setup process:
| $ rspec --only-failures |
| |
| To use `--only-failures`, you must first set ↩ |
| `config.example_status_persistence_file_path`. |
RSpec needs a place to store information about which examples are failing so that it knows what to rerun. You supply a filename through the RSpec.configure method, which is a catch-all for lots of different runtime options.
Add the following lines to your coffee_spec.rb file between the Coffee class definition and the specs:
| RSpec.configure do |config| |
| config.example_status_persistence_file_path = 'spec/examples.txt' |
| end |
You’ll need to rerun RSpec once without any flags (to record passing/failing status):
| $ rspec |
| .F |
| |
| truncated |
| |
| 2 examples, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:29 # A cup of coffee with milk costs $1.25 |
Now, you can use the --only-failures option:
| $ rspec --only-failures |
| Run options: include {:last_run_status=>"failed"} |
| F |
| |
| truncated |
| |
| 1 example, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:29 # A cup of coffee with milk costs $1.25 |
Let’s see what happens when the behavior gets fixed and the specs pass. Take a swing at modifying the Coffee class to pass both examples. Here’s one possible implementation:
| class Coffee |
| def ingredients |
| @ingredients ||= [] |
| end |
| |
| def add(ingredient) |
| ingredients << ingredient |
| end |
| |
| def price |
| 1.00 + ingredients.size * 0.25 |
| end |
| end |
With your implementation in place, rerun RSpec with the --only-failures option:
| $ rspec --only-failures |
| Run options: include {:last_run_status=>"failed"} |
| . |
| |
| Finished in 0.00094 seconds (files took 0.09055 seconds to load) |
| 1 example, 0 failures |
RSpec reruns the formerly failing example and verifies that it passes. If we try this process once more, RSpec won’t have any failing examples left to run:
| $ rspec --only-failures |
| Run options: include {:last_run_status=>"failed"} |
| |
| All examples were filtered out |
| |
| |
| Finished in 0.00031 seconds (files took 0.08117 seconds to load) |
| 0 examples, 0 failures |
Another command-line option, --next-failure, offers a twist on this idea. You’ll get a chance to try it out in the exercise at the end of this chapter.
Passing options to the rspec command isn’t the only way to run just a subset of your examples. Sometimes, it’s more convenient to make temporary annotations to your specs instead.
If you find yourself running the same subset of specs repeatedly, you can save time by marking them as focused. To do so, simply add an f to the beginning of the RSpec method name:
Let’s see what that looks like with the “A cup of coffee with milk costs $1.25” example. In coffee_spec.rb, replace context with fcontext (think of it as shorthand for focused context):
| fcontext 'with milk' do |
Next, we need to configure RSpec to run just the focused examples. Edit the RSpec.configure block in this file and add the following highlighted line:
| RSpec.configure do |config| |
» | config.filter_run_when_matching(focus: true) |
| config.example_status_persistence_file_path = 'spec/examples.txt' |
| end |
Now, when you run just rspec, it’ll run only the example in the focused context:
| $ rspec |
| Run options: include {:focus=>true} |
| . |
| |
| Finished in 0.00093 seconds (files took 0.07915 seconds to load) |
| 1 example, 0 failures |
If you haven’t marked any specs as focused, RSpec will run all of them.
We’d like to show you one more aspect of focused specs. Take a look at the first line of the output:
| Run options: include {:focus=>true} |
We saw something similar in the section on running only failed examples:
| Run options: include {:last_run_status=>"failed"} |
Although these two ways of slicing and dicing your specs feel very different, they’re both built on the same simple abstraction.
Earlier, when you wrote the following line to focus on the with milk context:
| fcontext 'with milk' do |
…this code was really just shorthand for the following expression:
| context 'with milk', focus: true do |
Any time you define an example or group—that is, any time you use RSpec.describe, context, or it—you can add a hash like the focus: true tag you see here. This hash, known as metadata, can contain arbitrary keys and values.
Behind the scenes, RSpec will add metadata of its own, such as last_run_status to indicate whether each spec passed or failed the last time it ran.
You can filter examples directly from the command line using the --tag option. For example, if RSpec didn’t already have an --only-failures command-line option, you could have gotten the same behavior like so:
| $ rspec --tag last_run_status:failed |
| Run options: include {:last_run_status=>"failed"} |
| F |
| |
| truncated |
| |
| 1 example, 1 failure |
| |
| Failed examples: |
| |
| rspec ./spec/coffee_spec.rb:29 # A cup of coffee with milk costs $1.25 |
Similarly, you could pass --tag focus to run just the focused specs, but instead we configured RSpec to do so by default.
Before continuing, don’t forget to change fcontext back to context. The whole idea of focusing is to filter specs temporarily.