Rspec tips and tricks

Running tests is crucial but can be time-consuming, lenghtening the feedback loop between code and side-effects. Here are some ways to run only the tests you need using Rspec, to stop wasting time staring at the screen.

Tags : Rspec Ruby Rails Testing DX

Published: March 13, 2024

Installing Rspec

Adding Rspec to a Rails app is as easy as running:

bundle add rspec-rails --group=test,development
bundle exec rails generate rspec:install

Running specific tests

When listing failures, Rspec prints every failure with the path to the file and the line number or group identifier (for generated tests and shared examples). Example:

Finished in 3.47 seconds (files took 4.35 seconds to load)
16 examples, 2 failures

Failed examples:

rspec ./spec/models/location_spec.rb:7 # [Assertion message]
rspec ./spec/requests/some_controller_spec.rb[1:1:1:1] # [Assertion message]

Pro tip: Triple-click and copy-paste any line to rerun exactly that test!

To run several lines in a file, simply tack them at the end of the file name. Example:

rspec spec/models/user_spec.rb:5:10:15 # Runs tests at line 5, 10 and 15

Note that you can also pass a line matching a context or describe group to run all examples inside them. It doesn’t matter if the line(s) don’t exactly match an it, context or describe block, Rspec simply moves up until it finds one, but beware that changes in the file may cause Rspec to run another test!

Rspec will run all test files (ending in _spec.rb) if you give it a folder name (or more). Example:

rspec spec/models/ spec/mailers # Runs all model and mailer specs

You can also use * to run files matching a pattern. Example:

rspec spec/models/user* # will run user_spec.rb, but also any file matching "user*_spec.rb"

Tagging

Adding tags to examples and groups is as easy as:

it "does something", :fancy do # works with context and describe blocks too

You can then run only tests that have this tag:

rspec --tag fancy # Run all fancy tests
rspec --tag fancy spec/models # Run only fancy model tests
rspec --tag ~fancy spec/models # Run all model tests except the fancy ones

Stop on first failure using --fail-fast

Rspec accepts the --fail-fast switch which causes it to stop immediately when a test fails. This is useful when debugging, particularly in situations where a single error causes multiple tests to fail. Most often, this happens when a factory fails to create objects.

Exiting immediately allows fixing the problem without waiting for the whole test suite to run.

Retry only failed tests with --only-failures

You can ask Rspec to only run specs that previously failed. For that, Rspec needs to remember which tests passed and which ones didn’t. To enable state persistence, open Rspec config (spec/spec_helper.rb) and uncomment the following line:

config.example_status_persistence_file_path = "spec/examples.txt"

You’ll need to tell git to ignore this file:

echo 'spec/examples.txt' >> .gitignore

You can combine this with --fail-fast to zoom in on problems even faster.

Going further

Please share your tips if you have more!