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.
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
- Read the manual!
rspec --help
lists all available features. - Add shell aliases for
rspec --only-failures
andrspec --fail-fast
to save some typing (and prevent typos) - Use aggregate failures to reduce setup time
- Generate all kinds of data: Faker
- Replace fixtures with factories: FactoryBot or Fabrication
- Clean database between runs: DatabaseCleaner
- Analyze test suite performance: TestProf —Gitlab reduced their CI by 40% after fixing issues!
Please share your tips if you have more!