Running Just What You Need

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.

Running Examples by Name

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.

Running Specific Failures

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

images/aside-icons/info.png

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.

Rerunning Everything That Failed

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:

02-running-specs/06/spec/coffee_spec.rb
 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:

02-running-specs/06/spec/coffee_spec.rb
 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.

Focusing Specific Examples

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):

02-running-specs/07/spec/coffee_spec.rb
 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:

02-running-specs/07/spec/coffee_spec.rb
 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.

Tag Filtering

Earlier, when you wrote the following line to focus on the with milk context:

02-running-specs/07/spec/coffee_spec.rb
 fcontext ​'with milk'​ ​do

…this code was really just shorthand for the following expression:

02-running-specs/08/spec/coffee_spec.rb
 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.