rspec-rails

rspec-rails
brings the RSpec testing framework to Ruby on Rails
as a drop-in alternative to its default testing framework, Minitest.
In RSpec, tests are not just scripts that verify your application code.
They’re also specifications (or specs, for short):
detailed explanations of how the application is supposed to behave,
expressed in plain English.
According to RSpec Rails new versioning strategy use:
Installation
IMPORTANT This README / branch refers to the 7.1.x stable release series, only bugfixes from this series will
be added here. See the main
branch on Github if you want or
require the latest unstable features.
-
Add rspec-rails
to both the :development
and :test
groups
of your app’s Gemfile
:
group :development, :test do
gem 'rspec-rails', '~> 7.0.0'
end
group :development, :test do
gem 'rspec-rails', git: 'https://github.com/rspec/rspec-rails'
end
(Adding it to the :development
group is not strictly necessary,
but without it, generators and rake tasks must be preceded by RAILS_ENV=test
.)
-
Then, in your project directory:
$ bundle install
$ rails generate rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
Upgrading
If your project is already using an older version of rspec-rails
,
upgrade to the latest version with:
$ bundle update rspec-rails
RSpec follows semantic versioning,
which means that “major version” upgrades (e.g., 2.x → 3.x)
come with breaking changes.
If you’re upgrading from version 2.x or below,
read the rspec-rails
upgrade notes to find out what to watch out for.
Be sure to check the general RSpec upgrade notes as well.
Usage
Creating boilerplate specs with rails generate
$ rails generate model user
invoke active_record
create db/migrate/20181017040312_create_users.rb
create app/models/user.rb
invoke rspec
create spec/models/user_spec.rb
$ rails generate rspec:model user
create spec/models/user_spec.rb
$ rails generate --help | grep rspec
Running specs
$ bundle exec rspec
$ bundle exec rspec spec/models
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb:8
$ bundle exec rspec --help
Optional: If bundle exec rspec
is too verbose for you,
you can generate a binstub at bin/rspec
and use that instead:
$ bundle binstubs rspec-core
RSpec DSL Basics (or, how do I write a spec?)
In RSpec, application behavior is described
first in (almost) plain English, then again in test code, like so:
RSpec.describe 'Post' do
context 'before publication' do
it 'cannot have comments' do
expect { Post.create.comments.create! }.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
Running rspec
will execute this test code,
and then use the plain-English descriptions
to generate a report of where the application
conforms to (or fails to meet) the spec:
$ rspec --format documentation spec/models/post_spec.rb
Post
before publication
cannot have comments
Failures:
1) Post before publication cannot have comments
Failure/Error: expect { Post.create.comments.create! }.to raise_error(ActiveRecord::RecordInvalid)
expected ActiveRecord::RecordInvalid but nothing was raised
# ./spec/models/post.rb:4:in `block (3 levels) in <top (required)>'
Finished in 0.00527 seconds (files took 0.29657 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/models/post_spec.rb:3 # Post before publication cannot have comments
For an in-depth look at the RSpec DSL, including lots of examples,
read the official Cucumber documentation for RSpec Core.
Helpful Rails Matchers
In RSpec, assertions are called expectations,
and every expectation is built around a matcher.
When you expect(a).to eq(b)
, you’re using the eq
matcher.
In addition to the matchers that come standard in RSpec,
here are some extras that make it easier
to test the various parts of a Rails system:
RSpec matcher | Delegates to | Available in | Notes |
---|
be_a_new | | all | primarily intended for controller specs |
render_template | assert_template | request / controller / view | use with expect(response).to |
redirect_to | assert_redirect | request / controller | use with expect(response).to |
route_to | assert_recognizes | routing / controller | use with expect(...).to route_to |
be_routable | | routing / controller | use with expect(...).not_to be_routable |
have_http_status | | request / controller / feature | |
match_array | | all | for comparing arrays of ActiveRecord objects |
have_been_enqueued | | all | requires config: ActiveJob::Base.queue_adapter = :test |
have_enqueued_job | | all | requires config: ActiveJob::Base.queue_adapter = :test |
Follow the links above for examples of how each matcher is used.
What else does RSpec Rails add?
For a comprehensive look at RSpec Rails’ features,
read the official Cucumber documentation.
What tests should I write?
RSpec Rails defines ten different types of specs
for testing different parts of a typical Rails application.
Each one inherits from one of Rails’ built-in TestCase
classes,
meaning the helper methods provided by default in Rails tests
are available in RSpec, as well.
Follow the links above to see examples of each spec type,
or for official Rails API documentation on the given TestCase
class.
Note: This is not a checklist.
Ask a hundred developers how to test an application,
and you’ll get a hundred different answers.
RSpec Rails provides thoughtfully selected features
to encourage good testing practices, but there’s no “right” way to do it.
Ultimately, it’s up to you to decide how your test suite will be composed.
When creating a spec file,
assign it a type in the top-level describe
block, like so:
RSpec.describe User, type: :model do
...
System specs, feature specs, request specs–what’s the difference?
RSpec Rails provides some end-to-end (entire application) testing capability
to specify the interaction with the client.
System specs
Also called acceptance tests, browser tests, or end-to-end tests,
system specs test the application from the perspective of a human client.
The test code walks through a user’s browser interactions,
visit '/login'
fill_in 'Name', with: 'jdoe'
and the expectations revolve around page content.
expect(page).to have_text('Welcome')
Because system specs are a wrapper around Rails’ built-in SystemTestCase
,
they’re only available on Rails 5.1+.
(Feature specs serve the same purpose, but without this dependency.)
Feature specs
Before Rails introduced system testing facilities,
feature specs were the only spec type for end-to-end testing.
While the RSpec team now officially recommends system specs instead,
feature specs are still fully supported, look basically identical,
and work on older versions of Rails.
On the other hand, feature specs require non-trivial configuration
to get some important features working,
like JavaScript testing or making sure each test runs with a fresh DB state.
With system specs, this configuration is provided out-of-the-box.
Like system specs, feature specs require the Capybara gem.
Rails 5.1+ includes it by default as part of system tests,
but if you don’t have the luxury of upgrading,
be sure to add it to the :test
group of your Gemfile
first:
group :test do
gem "capybara"
end
Request specs
Request specs are for testing the application
from the perspective of a machine client.
They begin with an HTTP request and end with the HTTP response,
so they’re faster than feature specs,
but do not examine your app’s UI or JavaScript.
Request specs provide a high-level alternative to controller specs.
In fact, as of RSpec 3.5, both the Rails and RSpec teams
discourage directly testing controllers
in favor of functional tests like request specs.
When writing them, try to answer the question,
“For a given HTTP request (verb + path + parameters),
what HTTP response should the application return?”
Contributing
Once you’ve cloned the repo and set up the environment,
you can run the specs and Cucumber features, or submit a pull request.
See Also
RSpec base libraries
Recommended third-party extensions