1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
|
# 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.
According to [RSpec Rails new versioning strategy][] use:
* **[`rspec-rails` 8.x][]** for Rails 8.0 or 7.2.
* **[`rspec-rails` 7.x][]** for Rails 7.x.
* **[`rspec-rails` 6.x][]** for Rails 6.1, 7.0 or 7.1.
* **[`rspec-rails` 5.x][]** for Rails 5.2 or 6.x.
* **[`rspec-rails` 4.x][]** for Rails from 5.x or 6.x.
* **[`rspec-rails` 3.x][]** for Rails earlier than 5.0.
* **[`rspec-rails` 1.x][]** for Rails 2.x.
[Code Climate]: https://codeclimate.com/github/rspec/rspec-rails.svg
[code-climate]: https://codeclimate.com/github/rspec/rspec-rails
[Gem Version]: https://badge.fury.io/rb/rspec-rails.svg
[gem-version]: https://badge.fury.io/rb/rspec-rails
[RSpec]: https://rspec.info/
[Ruby on Rails]: https://rubyonrails.org/
[`rspec-rails` 1.x]: https://github.com/dchelimsky/rspec-rails
[`rspec-rails` 3.x]: https://github.com/rspec/rspec-rails/tree/3-9-maintenance
[`rspec-rails` 4.x]: https://github.com/rspec/rspec-rails/tree/4-1-maintenance
[`rspec-rails` 5.x]: https://github.com/rspec/rspec-rails/tree/5-1-maintenance
[`rspec-rails` 6.x]: https://github.com/rspec/rspec-rails/tree/6-1-maintenance
[`rspec-rails` 7.x]: https://github.com/rspec/rspec-rails/tree/7-1-maintenance
[`rspec-rails` 8.x]: https://github.com/rspec/rspec-rails/tree/8-0-maintenance
[RSpec Rails new versioning strategy]: https://github.com/rspec/rspec-rails/blob/main/rfcs/versioning-strategy.md
## Installation
**IMPORTANT** This README / branch refers to the 8.0.x stable release series, only bugfixes from this series will
be added here. See the [`main` branch on Github](https://github.com/rspec/rspec-rails/tree/main) if you want or
require the latest unstable features.https://github.com/rspec/rspec-rails/tree/8-0-maintenance) if you want or require the latest stable release.
1. Add `rspec-rails` to **both** the `:development` and `:test` groups
of your app’s `Gemfile`:
```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 `:development` group is not strictly necessary,
but without it, generators and rake tasks must be preceded by `RAILS_ENV=test`.)
2. 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:
```sh
$ bundle update rspec-rails
```
RSpec follows [semantic versioning](https://semver.org/),
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.
[`rspec-rails` upgrade notes]: https://rspec.info/features/8-0/rspec-rails/upgrade
[RSpec upgrade notes]: https://rspec.info/upgrading-from-rspec-2/
## Usage
### Creating boilerplate specs with `rails generate`
```sh
# 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 rspec
```
### Running specs
```sh
# 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 --help
```
**Optional:** If `bundle exec rspec` is too verbose for you,
you can generate a binstub at `bin/rspec` and use that instead:
```sh
$ 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:
```ruby
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
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][].
[RSpec Core]: https://rspec.info/features/3-12/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.
[the matchers that come standard in RSpec]: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers
[`be_a_new`]: https://rspec.info/features/8-0/rspec-rails/matchers/new-record-matcher
[`render_template`]: https://rspec.info/features/8-0/rspec-rails/matchers/render-template-matcher
[`redirect_to`]: https://rspec.info/features/8-0/rspec-rails/matchers/redirect-to-matcher
[`route_to`]: https://rspec.info/features/8-0/rspec-rails/routing-specs/route-to-matcher
[`be_routable`]: https://rspec.info/features/8-0/rspec-rails/routing-specs/be-routable-matcher
[`have_http_status`]: https://rspec.info/features/8-0/rspec-rails/matchers/have-http-status-matcher
[`match_array`]: https://rspec.info/features/8-0/rspec-rails/matchers/relation-match-array
[`have_been_enqueued`]: https://rspec.info/features/8-0/rspec-rails/matchers/have-been-enqueued-matcher
[`have_enqueued_job`]: https://rspec.info/features/8-0/rspec-rails/matchers/have-enqueued-job-matcher
### What else does RSpec Rails add?
For a comprehensive look at RSpec Rails’ features,
read the [official Cucumber documentation][].
[official Cucumber documentation]: https://rspec.info/features/8-0/rspec-rails
## 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:
```ruby
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
...
```
[request]: https://rspec.info/features/8-0/rspec-rails/request-specs/request-spec
[feature]: https://rspec.info/features/8-0/rspec-rails/feature-specs/feature-spec
[system]: https://rspec.info/features/8-0/rspec-rails/system-specs/system-specs
[model]: https://rspec.info/features/8-0/rspec-rails/model-specs
[controller]: https://rspec.info/features/8-0/rspec-rails/controller-specs
[mailer]: https://rspec.info/features/8-0/rspec-rails/mailer-specs
[job]: https://rspec.info/features/8-0/rspec-rails/job-specs/job-spec
[view]: https://rspec.info/features/8-0/rspec-rails/view-specs/view-spec
[routing]: https://rspec.info/features/8-0/rspec-rails/routing-specs
[helper]: https://rspec.info/features/8-0/rspec-rails/helper-specs/helper-spec
[`ActionDispatch::IntegrationTest`]: https://api.rubyonrails.org/classes/ActionDispatch/IntegrationTest.html
[`ActionDispatch::SystemTestCase`]: https://api.rubyonrails.org/classes/ActionDispatch/SystemTestCase.html
[`ActionController::TestCase`]: https://api.rubyonrails.org/classes/ActionController/TestCase.html
[in the appropriate folder]: https://rspec.info/features/8-0/rspec-rails/directory-structure
### 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:
```ruby
group :test do
gem "capybara"
end
```
[officially recommends system specs]: https://rspec.info/blog/2017/10/rspec-3-7-has-been-released/#rails-actiondispatchsystemtest-integration-system-specs
[Capybara]: https://github.com/teamcapybara/capybara
#### 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?”
[discourage directly testing controllers]: https://rspec.info/blog/2016/07/rspec-3-5-has-been-released/#rails-support-for-rails-5
## Contributing
- [Build details](BUILD_DETAIL.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Detailed contributing guide](CONTRIBUTING.md)
Once you’ve cloned the repo and [set up the environment](DEVELOPMENT.md),
you can run the specs and Cucumber features, or submit a pull request.
## See Also
### RSpec base libraries
* https://github.com/rspec/rspec
### Recommended third-party extensions
* [FactoryBot](https://github.com/thoughtbot/factory_bot)
* [Capybara](https://github.com/teamcapybara/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.)
[additional configuration is required]: https://rubydoc.info/gems/rspec-rails/file/Capybara.md
|