Technical Documentation: rspec/rspec-rails
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
rspec-rails [![Code Climate][]][code-climate] [![Gem Version][]][gem-version]
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.
Supported Versions
We follow a versioning strategy as defined by RSpec Rails versioning strategy the
TL;DR of which is that we support currently supported versions of Rails, and will
issue a major version change when removing older versions from support.
Accordingly you should use:
rspec-rails8.x for Rails 8.0 or 7.2.rspec-rails7.x for Rails 7.x.rspec-rails6.x for Rails 6.1, 7.0 or 7.1.rspec-rails5.x for Rails 5.2 or 6.x.rspec-rails4.x for Rails from 5.x or 6.x.rspec-rails3.x for Rails earlier than 5.0.rspec-rails1.x for Rails 2.x.
Installation
IMPORTANT This README / branch refers to the current development build.
See the 8-0-maintenance branch on Github if you want or require the latest stable release.
Add
rspec-railsto both the:developmentand:testgroups
of your app’sGemfile:ruby# Run against this stable release group :development, :test do gem 'rspec-rails', '~> 8.0.0' end # Or, run against the main branch group :development, :test do gem 'rspec-rails', git: 'https://github.com/rspec/rspec-rails' end(Adding it to the
:developmentgroup is not strictly necessary,
but without it, generators and rake tasks must be preceded byRAILS_ENV=test.)Then, in your project directory:
sh# Download and install $ bundle install # Generate boilerplate configuration files # (check the comments in each generated file for more information) $ 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-railsRSpec 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`
# RSpec hooks into built-in generators
$ 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
# RSpec also provides its own spec file generators
$ rails generate rspec:model user
create spec/models/user_spec.rb
# List all RSpec generators
$ rails generate --help | grep rspecRunning specs
# Default: Run all spec files (i.e., those matching spec/**/*_spec.rb)
$ bundle exec rspec
# Run all spec files in a single directory (recursively)
$ bundle exec rspec spec/models
# Run a single spec file
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb
# Run a single example from a spec file (by line number)
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb:8
# See all options for running specs
$ bundle exec rspec --helpOptional: If bundle exec rspec is too verbose for you,
you can generate a binstub at bin/rspec and use that instead:
$ bundle binstubs rspec-coreRSpec 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 # (almost) plain English
it 'cannot have comments' do #
expect { Post.create.comments.create! }.to raise_error(ActiveRecord::RecordInvalid) # test code
end
end
endRunning 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 commentsFor 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.
| Spec type | Corresponding Rails test class |
|---|---|
| model | |
| controller | ActionController::TestCase |
| mailer | ActionMailer::TestCase |
| job | |
| view | ActionView::TestCase |
| routing | |
| helper | ActionView::TestCase |
| request | ActionDispatch::IntegrationTest |
| feature | |
| system | ActionDispatch::SystemTestCase |
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:
# spec/models/user_spec.rb
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"
endRequest 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
Capybara
(Included by default in Rails 5.1+.
Note that additional configuration is required to use the Capybara DSL
anywhere other than system specs and feature specs.)
Overview (`features/README.md`)
RSpec Rails
rspec-rails extends Rails' built-in testing framework to support rspec
examples for requests, controllers, models, views, helpers, mailers and
routing. It is a thin framework around Rails own helpers and you can
check their documentation for help as well.
Rails
rspec-rails 7 supports Rails 7.0 to 7.2. For earlier versions of Rails, you
should use rspec-rails-6
for Rails 6.1, rspec-rails-5
for Rails 5.2 and 6.0, rspec-rails-4
for Rails 5.x, and rspec-rails 3
for even older versions.
Install
gem install rspec-railsThis installs the following gems:
rspec
rspec-core
rspec-expectations
rspec-mocks
rspec-railsConfigure
Add rspec-rails to the :test and :development groups in the Gemfile:
group :test, :development do
gem 'rspec-rails', '~> 7.0.0'
endIt needs to be in the :development group to expose generators and rake tasks
without having to type RAILS_ENV=test.
Now you can run:
bundle exec rails generate rspec:installThis adds the spec directory and some skeleton files, including a .rspec
file.
You can also customize the default spec path with --default-path option:
bundle exec rails generate rspec:install --default-path behaviourIssues
The documentation for rspec-rails is a work in progress. We'll be adding
Cucumber features over time, and clarifying existing ones. If you have
specific features you'd like to see added, find the existing documentation
incomplete or confusing, or, better yet, wish to write a missing Cucumber
feature yourself, please submit an
issue or a pull
request.
Overview (`features/controller_specs/README.md`)
Controller specs
Controller specs are marked by type: :controller or if you have setconfig.infer_spec_type_from_file_location! by placing them in spec/controllers.
A controller spec is an RSpec wrapper for a Rails functional test
(ActionController::TestCase::Behavior).
It allows you to simulate a single http request in each example, and then
specify expected outcomes such as:
- rendered templates
- redirects
- instance variables assigned in the controller to be shared with the view
- cookies sent back with the response
To specify outcomes, you can use:
- standard rspec matchers (
expect(response.status).to eq(200)) - standard test/unit assertions (
assert_equal 200, response.status) - rails assertions (
assert_response 200) - rails-specific matchers:
-
ruby
expect(response).to render_template(:new) # wraps assert_template -
ruby
expect(response).to redirect_to(location) # wraps assert_redirected_to -
ruby
expect(response).to have_http_status(:created) -
ruby
expect(assigns(:widget)).to be_a_new(Widget)
-
Examples
RSpec.describe TeamsController do
describe "GET index" do
it "assigns @teams" do
team = Team.create
get :index
expect(assigns(:teams)).to eq([team])
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
end
end
endViews
- by default, views are not rendered. See
views are stubbed by default and
render_views for details.
Headers
We encourage you to use request specs if you want to set headers in your call. If you still want to use controller specs with custom http headers you can use request.headers:
require "rails_helper"
RSpec.describe TeamsController, type: :controller do
describe "GET index" do
it "returns a 200" do
request.headers["Authorization"] = "foo"
get :show
expect(response).to have_http_status(:ok)
end
end
endOverview (`features/mailer_specs/README.md`)
Mailer specs
By default Mailer specs reside in the spec/mailers folder. Adding the metadatatype: :mailer to any context makes its examples be treated as mailer specs.
A mailer spec is a thin wrapper for an ActionMailer::TestCase, and includes all
of the behavior and assertions that it provides, in addition to RSpec's own
behavior and expectations.
Examples
require "rails_helper"
RSpec.describe Notifications, type: :mailer do
describe "notify" do
let(:mail) { Notifications.signup }
it "renders the headers" do
expect(mail.subject).to eq("Signup")
expect(mail.to).to eq(["[email protected]"])
expect(mail.from).to eq(["[email protected]"])
end
it "renders the body" do
expect(mail.body.encoded).to match("Hi")
end
end
endOverview (`features/matchers/README.md`)
Matchers
rspec-rails offers a number of custom matchers, most of which are
rspec-compatible wrappers for Rails' assertions.
redirects
# delegates to assert_redirected_to
expect(response).to redirect_to(path)templates
# delegates to assert_template
expect(response).to render_template(template_name)assigned objects
# passes if assigns(:widget) is an instance of Widget
# and it is not persisted
expect(assigns(:widget)).to be_a_new(Widget)Overview (`features/model_specs/README.md`)
Model specs
Model specs are marked by type: :model or if you have setconfig.infer_spec_type_from_file_location! by placing them in spec/models.
A model spec is a thin wrapper for an ActiveSupport::TestCase, and includes all
of the behavior and assertions that it provides, in addition to RSpec's own
behavior and expectations.
Examples
require "rails_helper"
RSpec.describe Post, type: :model do
context "with 2 or more comments" do
it "orders them in reverse chronologically" do
post = Post.create!
comment1 = post.comments.create!(:body => "first comment")
comment2 = post.comments.create!(:body => "second comment")
expect(post.reload.comments).to eq([comment2, comment1])
end
end
endOverview (`features/routing_specs/README.md`)
Routing specs
Routing specs are marked by type: :routing or if you have setconfig.infer_spec_type_from_file_location! by placing them in spec/routing.
Simple apps with nothing but standard RESTful routes won't get much value from
routing specs, but they can provide significant value when used to specify
customized routes, like vanity links, slugs, etc.
expect(:get => "/articles/2012/11/when-to-use-routing-specs").to route_to(
:controller => "articles",
:month => "2012-11",
:slug => "when-to-use-routing-specs"
)They are also valuable for routes that should not be available:
expect(:delete => "/accounts/37").not_to be_routableOverview (`features/upgrade/README.md`)
Upgrading
RSpec Rails versions follow semantic versioning of x.y.z where:
xis a major release containing breaking changes and support changes for Rails.yis a minor release which will contain only feature additions and bug fixes.zis a patch release which will contain only bug fixes for the minor levels currently supported version of Rails.
On new Rails minor releases we will usually release our own new minor version to support that version, occasionally
we will release a new major version instead to allow us to remove support for now unsupported versions of Rails
as defined by the Rails team themselves.
The RSpec team will only maintain the current major / minor version, although it is common for the main branch
to contain changes for the next upcoming version of Rails and usage of this branch directly is also supported.
Upgrading from rspec-rails 6.x to version 7
RSpec Rails 7 supports Rails versions 7.0, 7.1 and 7.2. There are no changes required to upgrade from 6.x to 7 for these versions of Rails,
but we encourage those doing multiple step upgrades to upgrade to Rails 7.1 and RSpec Rails 6.1.x before upgrading to Rails 7.2 and RSpec Rails 7.0.
If you are on Rails 6.1 you will need to keep using RSpec Rails 6.1.
Upgrading from rspec-rails 5.x to version 6
RSpec Rails 6 supports Rails versions 6.1, 7.0 and 7.1. There are no changes required to upgrade from 5.x to 6 for these versions of Rails.
Upgrading from rspec-rails 4.x to version 5
RSpec Rails 5 supports 5.2, 6.0 and 6.1. There are no changes required to upgrade from 4.x to 5 for these versions of Rails.
If you are using an older version of Rails, you can use 4.x which hard supports 5.0 and 5.1, and soft supports 4.2 (which is unmaintained).
Upgrading from rspec-rails 3.x to version 4
RSpec Rails 4 was the first version to be released out of step with rspec, as a major version under semantic versioning, it allowed us to change the supported Rails versions to 5 and 6 only.
There are no changes required to upgrade to RSpec Rails 4 from 3.x if you are using Rails 5 or 6.
If you are using Rails 4.2 you can use RSpec Rails 4, but note that support for it is not maintained, we consider this a breaking change hence the version change, and you must be on Ruby 2.2 as a minimum.
If you are upgrading from an earlier version of RSpec Rails, please consult the upgrading 2.x to 3.x guide.
--- METRICS ---
- Files Extracted: 8
- Estimated Token Budget: ~6463 tokens
- Canonical Reference: https://codewiki.google/github.com/rspec/rspec-rails