rails 4.0.0 → 4.2.11.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +30 -23
- data/guides/CHANGELOG.md +108 -6
- data/guides/Rakefile +21 -6
- data/guides/assets/images/akshaysurve.jpg +0 -0
- data/guides/assets/images/edge_badge.png +0 -0
- data/guides/assets/images/feature_tile.gif +0 -0
- data/guides/assets/images/footer_tile.gif +0 -0
- data/guides/assets/images/fxn.png +0 -0
- data/guides/assets/images/getting_started/article_with_comments.png +0 -0
- data/guides/assets/images/getting_started/challenge.png +0 -0
- data/guides/assets/images/getting_started/confirm_dialog.png +0 -0
- data/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +0 -0
- data/guides/assets/images/getting_started/form_with_errors.png +0 -0
- data/guides/assets/images/getting_started/index_action_with_edit_link.png +0 -0
- data/guides/assets/images/getting_started/new_article.png +0 -0
- data/guides/assets/images/getting_started/rails_welcome.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
- data/guides/assets/images/getting_started/show_action_for_articles.png +0 -0
- data/guides/assets/images/getting_started/template_is_missing_articles_new.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_articles.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_new_for_articles.png +0 -0
- data/guides/assets/images/header_tile.gif +0 -0
- data/guides/assets/images/icons/README +1 -1
- data/guides/assets/images/icons/callouts/11.png +0 -0
- data/guides/assets/images/icons/callouts/12.png +0 -0
- data/guides/assets/images/icons/callouts/13.png +0 -0
- data/guides/assets/images/icons/callouts/15.png +0 -0
- data/guides/assets/images/icons/caution.png +0 -0
- data/guides/assets/images/icons/example.png +0 -0
- data/guides/assets/images/radar.png +0 -0
- data/guides/assets/images/rails4_features.png +0 -0
- data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
- data/guides/assets/images/vijaydev.jpg +0 -0
- data/guides/assets/javascripts/guides.js +36 -34
- data/guides/assets/stylesheets/main.css +6 -2
- data/guides/assets/stylesheets/print.css +1 -1
- data/guides/bug_report_templates/action_controller_gem.rb +47 -0
- data/guides/bug_report_templates/action_controller_master.rb +54 -0
- data/guides/bug_report_templates/active_record_gem.rb +5 -2
- data/guides/bug_report_templates/active_record_master.rb +3 -2
- data/guides/bug_report_templates/generic_gem.rb +15 -0
- data/guides/bug_report_templates/generic_master.rb +26 -0
- data/guides/rails_guides.rb +23 -4
- data/guides/rails_guides/generator.rb +1 -1
- data/guides/rails_guides/helpers.rb +4 -2
- data/guides/rails_guides/levenshtein.rb +27 -21
- data/guides/rails_guides/markdown.rb +11 -7
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/source/2_2_release_notes.md +3 -3
- data/guides/source/2_3_release_notes.md +12 -12
- data/guides/source/3_0_release_notes.md +10 -13
- data/guides/source/3_1_release_notes.md +7 -4
- data/guides/source/3_2_release_notes.md +17 -14
- data/guides/source/4_0_release_notes.md +110 -54
- data/guides/source/4_1_release_notes.md +730 -0
- data/guides/source/4_2_release_notes.md +877 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +6 -2
- data/guides/source/action_controller_overview.md +223 -57
- data/guides/source/action_mailer_basics.md +129 -76
- data/guides/source/action_view_overview.md +247 -246
- data/guides/source/active_job_basics.md +339 -0
- data/guides/source/active_model_basics.md +374 -20
- data/guides/source/active_record_basics.md +46 -45
- data/guides/source/active_record_callbacks.md +83 -28
- data/guides/source/{migrations.md → active_record_migrations.md} +191 -275
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +382 -300
- data/guides/source/active_record_validations.md +64 -55
- data/guides/source/active_support_core_extensions.md +229 -187
- data/guides/source/active_support_instrumentation.md +23 -22
- data/guides/source/api_documentation_guidelines.md +167 -15
- data/guides/source/asset_pipeline.md +768 -294
- data/guides/source/association_basics.md +188 -96
- data/guides/source/autoloading_and_reloading_constants.md +1311 -0
- data/guides/source/caching_with_rails.md +45 -11
- data/guides/source/command_line.md +96 -65
- data/guides/source/configuring.md +404 -70
- data/guides/source/contributing_to_ruby_on_rails.md +270 -130
- data/guides/source/credits.html.erb +7 -3
- data/guides/source/debugging_rails_applications.md +471 -284
- data/guides/source/development_dependencies_install.md +115 -21
- data/guides/source/documents.yaml +31 -9
- data/guides/source/engines.md +737 -291
- data/guides/source/form_helpers.md +137 -89
- data/guides/source/generators.md +60 -28
- data/guides/source/getting_started.md +1007 -596
- data/guides/source/i18n.md +178 -96
- data/guides/source/index.html.erb +2 -1
- data/guides/source/initialization.md +248 -104
- data/guides/source/kindle/toc.html.erb +1 -1
- data/guides/source/layout.html.erb +14 -22
- data/guides/source/layouts_and_rendering.md +78 -46
- data/guides/source/maintenance_policy.md +78 -0
- data/guides/source/nested_model_forms.md +10 -7
- data/guides/source/plugins.md +66 -57
- data/guides/source/rails_application_templates.md +49 -12
- data/guides/source/rails_on_rack.md +50 -60
- data/guides/source/routing.md +190 -139
- data/guides/source/ruby_on_rails_guides_guidelines.md +12 -13
- data/guides/source/security.md +134 -83
- data/guides/source/testing.md +322 -200
- data/guides/source/upgrading_ruby_on_rails.md +834 -37
- data/guides/source/working_with_javascript_in_rails.md +36 -26
- data/guides/w3c_validator.rb +2 -0
- metadata +93 -116
- data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
- data/guides/assets/images/getting_started/new_post.png +0 -0
- data/guides/assets/images/getting_started/post_with_comments.png +0 -0
- data/guides/assets/images/getting_started/show_action_for_posts.png +0 -0
- data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
- data/guides/assets/images/getting_started/undefined_method_post_path.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
- data/guides/assets/images/jaimeiniesta.jpg +0 -0
- data/guides/code/getting_started/Gemfile +0 -43
- data/guides/code/getting_started/Gemfile.lock +0 -150
- data/guides/code/getting_started/README.rdoc +0 -28
- data/guides/code/getting_started/Rakefile +0 -6
- data/guides/code/getting_started/app/assets/javascripts/application.js +0 -16
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
- data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
- data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -17
- data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -47
- data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
- data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
- data/guides/code/getting_started/app/models/comment.rb +0 -3
- data/guides/code/getting_started/app/models/post.rb +0 -7
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
- data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
- data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
- data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
- data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
- data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
- data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -3
- data/guides/code/getting_started/bin/bundle +0 -4
- data/guides/code/getting_started/bin/rails +0 -4
- data/guides/code/getting_started/bin/rake +0 -4
- data/guides/code/getting_started/config.ru +0 -4
- data/guides/code/getting_started/config/application.rb +0 -18
- data/guides/code/getting_started/config/boot.rb +0 -4
- data/guides/code/getting_started/config/database.yml +0 -25
- data/guides/code/getting_started/config/environment.rb +0 -5
- data/guides/code/getting_started/config/environments/development.rb +0 -30
- data/guides/code/getting_started/config/environments/production.rb +0 -80
- data/guides/code/getting_started/config/environments/test.rb +0 -36
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
- data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
- data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
- data/guides/code/getting_started/config/initializers/locale.rb +0 -9
- data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
- data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
- data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
- data/guides/code/getting_started/config/locales/en.yml +0 -23
- data/guides/code/getting_started/config/routes.rb +0 -7
- data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
- data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
- data/guides/code/getting_started/db/schema.rb +0 -33
- data/guides/code/getting_started/db/seeds.rb +0 -7
- data/guides/code/getting_started/public/404.html +0 -58
- data/guides/code/getting_started/public/422.html +0 -58
- data/guides/code/getting_started/public/500.html +0 -57
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +0 -5
- data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
- data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
- data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
- data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
- data/guides/code/getting_started/test/models/comment_test.rb +0 -7
- data/guides/code/getting_started/test/models/post_test.rb +0 -7
- data/guides/code/getting_started/test/test_helper.rb +0 -15
- data/guides/source/kindle/KINDLE.md +0 -26
data/guides/source/testing.md
CHANGED
@@ -49,7 +49,9 @@ The `test_helper.rb` file holds the default configuration for your tests.
|
|
49
49
|
|
50
50
|
### The Low-Down on Fixtures
|
51
51
|
|
52
|
-
For good tests, you'll need to give some thought to setting up test data.
|
52
|
+
For good tests, you'll need to give some thought to setting up test data.
|
53
|
+
In Rails, you can handle this by defining and customizing fixtures.
|
54
|
+
You can find comprehensive documentation in the [fixture api documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
|
53
55
|
|
54
56
|
#### What Are Fixtures?
|
55
57
|
|
@@ -64,20 +66,42 @@ YAML-formatted fixtures are a very human-friendly way to describe your sample da
|
|
64
66
|
Here's a sample YAML fixture file:
|
65
67
|
|
66
68
|
```yaml
|
67
|
-
# lo & behold!
|
69
|
+
# lo & behold! I am a YAML comment!
|
68
70
|
david:
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
name: David Heinemeier Hansson
|
72
|
+
birthday: 1979-10-15
|
73
|
+
profession: Systems development
|
72
74
|
|
73
75
|
steve:
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
name: Steve Ross Kellock
|
77
|
+
birthday: 1974-09-27
|
78
|
+
profession: guy with keyboard
|
77
79
|
```
|
78
80
|
|
79
81
|
Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank space. You can place comments in a fixture file by using the # character in the first column. Keys which resemble YAML keywords such as 'yes' and 'no' are quoted so that the YAML Parser correctly interprets them.
|
80
82
|
|
83
|
+
If you are working with [associations](/association_basics.html), you can simply
|
84
|
+
define a reference node between two different fixtures. Here's an example with
|
85
|
+
a `belongs_to`/`has_many` association:
|
86
|
+
|
87
|
+
```yaml
|
88
|
+
# In fixtures/categories.yml
|
89
|
+
about:
|
90
|
+
name: About
|
91
|
+
|
92
|
+
# In fixtures/articles.yml
|
93
|
+
one:
|
94
|
+
title: Welcome to Rails!
|
95
|
+
body: Hello world!
|
96
|
+
category: about
|
97
|
+
```
|
98
|
+
|
99
|
+
Note: For associations to reference one another by name, you cannot specify the `id:`
|
100
|
+
attribute on the fixtures. Rails will auto assign a primary key to be consistent between
|
101
|
+
runs. If you manually specify an `id:` attribute, this behavior will not work. For more
|
102
|
+
information on this association behavior please read the
|
103
|
+
[fixture api documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
|
104
|
+
|
81
105
|
#### ERB'in It Up
|
82
106
|
|
83
107
|
ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users:
|
@@ -92,7 +116,7 @@ user_<%= n %>:
|
|
92
116
|
|
93
117
|
#### Fixtures in Action
|
94
118
|
|
95
|
-
Rails by default automatically loads all fixtures from the `test/fixtures` folder for your
|
119
|
+
Rails by default automatically loads all fixtures from the `test/fixtures` folder for your models and controllers test. Loading involves three steps:
|
96
120
|
|
97
121
|
* Remove any existing data from the table corresponding to the fixture
|
98
122
|
* Load the fixture data into the table
|
@@ -116,29 +140,29 @@ email(david.girlfriend.email, david.location_tonight)
|
|
116
140
|
Unit Testing your Models
|
117
141
|
------------------------
|
118
142
|
|
119
|
-
In Rails,
|
143
|
+
In Rails, models tests are what you write to test your models.
|
120
144
|
|
121
|
-
For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices.
|
145
|
+
For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. We will be using examples from this generated code and will be supplementing it with additional examples where necessary.
|
122
146
|
|
123
|
-
NOTE: For more information on Rails
|
147
|
+
NOTE: For more information on Rails _scaffolding_, refer to [Getting Started with Rails](getting_started.html)
|
124
148
|
|
125
149
|
When you use `rails generate scaffold`, for a resource among other things it creates a test stub in the `test/models` folder:
|
126
150
|
|
127
151
|
```bash
|
128
|
-
$ rails generate scaffold
|
152
|
+
$ bin/rails generate scaffold article title:string body:text
|
129
153
|
...
|
130
|
-
create app/models/
|
131
|
-
create test/models/
|
132
|
-
create test/fixtures/
|
154
|
+
create app/models/article.rb
|
155
|
+
create test/models/article_test.rb
|
156
|
+
create test/fixtures/articles.yml
|
133
157
|
...
|
134
158
|
```
|
135
159
|
|
136
|
-
The default test stub in `test/models/
|
160
|
+
The default test stub in `test/models/article_test.rb` looks like this:
|
137
161
|
|
138
162
|
```ruby
|
139
163
|
require 'test_helper'
|
140
164
|
|
141
|
-
class
|
165
|
+
class ArticleTest < ActiveSupport::TestCase
|
142
166
|
# test "the truth" do
|
143
167
|
# assert true
|
144
168
|
# end
|
@@ -154,15 +178,15 @@ require 'test_helper'
|
|
154
178
|
As you know by now, `test_helper.rb` specifies the default configuration to run our tests. This is included with all the tests, so any methods added to this file are available to all your tests.
|
155
179
|
|
156
180
|
```ruby
|
157
|
-
class
|
181
|
+
class ArticleTest < ActiveSupport::TestCase
|
158
182
|
```
|
159
183
|
|
160
|
-
The `
|
184
|
+
The `ArticleTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `ArticleTest` thus has all the methods available from `ActiveSupport::TestCase`. You'll see those methods a little later in this guide.
|
161
185
|
|
162
|
-
Any method defined within a class inherited from `
|
163
|
-
(which is the superclass of `ActiveSupport::TestCase`) that begins with `
|
186
|
+
Any method defined within a class inherited from `Minitest::Test`
|
187
|
+
(which is the superclass of `ActiveSupport::TestCase`) that begins with `test_` (case sensitive) is simply called a test. So, `test_password` and `test_valid_password` are legal test names and are run automatically when the test case is run.
|
164
188
|
|
165
|
-
Rails adds a `test` method that takes a test name and a block. It generates a normal `
|
189
|
+
Rails adds a `test` method that takes a test name and a block. It generates a normal `Minitest::Unit` test with method names prefixed with `test_`. So,
|
166
190
|
|
167
191
|
```ruby
|
168
192
|
test "the truth" do
|
@@ -195,38 +219,25 @@ This line of code is called an _assertion_. An assertion is a line of code that
|
|
195
219
|
|
196
220
|
Every test contains one or more assertions. Only when all the assertions are successful will the test pass.
|
197
221
|
|
198
|
-
###
|
199
|
-
|
200
|
-
Before you can run your tests, you need to ensure that the test database structure is current. For this you can use the following rake commands:
|
201
|
-
|
202
|
-
```bash
|
203
|
-
$ rake db:migrate
|
204
|
-
...
|
205
|
-
$ rake db:test:load
|
206
|
-
```
|
207
|
-
|
208
|
-
The `rake db:migrate` above runs any pending migrations on the _development_ environment and updates `db/schema.rb`. The `rake db:test:load` recreates the test database from the current `db/schema.rb`. On subsequent attempts, it is a good idea to first run `db:test:prepare`, as it first checks for pending migrations and warns you appropriately.
|
209
|
-
|
210
|
-
NOTE: `db:test:prepare` will fail with an error if `db/schema.rb` doesn't exist.
|
211
|
-
|
212
|
-
#### Rake Tasks for Preparing your Application for Testing
|
222
|
+
### Maintaining the test database schema
|
213
223
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
224
|
+
In order to run your tests, your test database will need to have the current
|
225
|
+
structure. The test helper checks whether your test database has any pending
|
226
|
+
migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql`
|
227
|
+
into the test database. If migrations are still pending, an error will be
|
228
|
+
raised. Usually this indicates that your schema is not fully migrated. Running
|
229
|
+
the migrations against the development database (`bin/rake db:migrate`) will
|
230
|
+
bring the schema up to date.
|
221
231
|
|
222
|
-
|
232
|
+
NOTE: If existing migrations required modifications, the test database needs to
|
233
|
+
be rebuilt. This can be done by executing `bin/rake db:test:prepare`.
|
223
234
|
|
224
235
|
### Running Tests
|
225
236
|
|
226
237
|
Running a test is as simple as invoking the file containing the test cases through `rake test` command.
|
227
238
|
|
228
239
|
```bash
|
229
|
-
$ rake test test/models/
|
240
|
+
$ bin/rake test test/models/article_test.rb
|
230
241
|
.
|
231
242
|
|
232
243
|
Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
|
@@ -237,7 +248,7 @@ Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
|
|
237
248
|
You can also run a particular test method from the test case by running the test and providing the `test method name`.
|
238
249
|
|
239
250
|
```bash
|
240
|
-
$ rake test test/models/
|
251
|
+
$ bin/rake test test/models/article_test.rb test_the_truth
|
241
252
|
.
|
242
253
|
|
243
254
|
Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s.
|
@@ -249,25 +260,25 @@ This will run all test methods from the test case. Note that `test_helper.rb` is
|
|
249
260
|
|
250
261
|
The `.` (dot) above indicates a passing test. When a test fails you see an `F`; when a test throws an error you see an `E` in its place. The last line of the output is the summary.
|
251
262
|
|
252
|
-
To see how a test failure is reported, you can add a failing test to the `
|
263
|
+
To see how a test failure is reported, you can add a failing test to the `article_test.rb` test case.
|
253
264
|
|
254
265
|
```ruby
|
255
|
-
test "should not save
|
256
|
-
|
257
|
-
|
266
|
+
test "should not save article without title" do
|
267
|
+
article = Article.new
|
268
|
+
assert_not article.save
|
258
269
|
end
|
259
270
|
```
|
260
271
|
|
261
272
|
Let us run this newly added test.
|
262
273
|
|
263
274
|
```bash
|
264
|
-
$ rake test test/models/
|
275
|
+
$ bin/rake test test/models/article_test.rb test_should_not_save_article_without_title
|
265
276
|
F
|
266
277
|
|
267
278
|
Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s.
|
268
279
|
|
269
280
|
1) Failure:
|
270
|
-
|
281
|
+
test_should_not_save_article_without_title(ArticleTest) [test/models/article_test.rb:6]:
|
271
282
|
Failed assertion, no message given.
|
272
283
|
|
273
284
|
1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
|
@@ -276,9 +287,9 @@ Failed assertion, no message given.
|
|
276
287
|
In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message which mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here:
|
277
288
|
|
278
289
|
```ruby
|
279
|
-
test "should not save
|
280
|
-
|
281
|
-
|
290
|
+
test "should not save article without title" do
|
291
|
+
article = Article.new
|
292
|
+
assert_not article.save, "Saved the article without a title"
|
282
293
|
end
|
283
294
|
```
|
284
295
|
|
@@ -286,14 +297,14 @@ Running this test shows the friendlier assertion message:
|
|
286
297
|
|
287
298
|
```bash
|
288
299
|
1) Failure:
|
289
|
-
|
290
|
-
Saved the
|
300
|
+
test_should_not_save_article_without_title(ArticleTest) [test/models/article_test.rb:6]:
|
301
|
+
Saved the article without a title
|
291
302
|
```
|
292
303
|
|
293
304
|
Now to get this test to pass we can add a model level validation for the _title_ field.
|
294
305
|
|
295
306
|
```ruby
|
296
|
-
class
|
307
|
+
class Article < ActiveRecord::Base
|
297
308
|
validates :title, presence: true
|
298
309
|
end
|
299
310
|
```
|
@@ -301,7 +312,7 @@ end
|
|
301
312
|
Now the test should pass. Let us verify by running the test again:
|
302
313
|
|
303
314
|
```bash
|
304
|
-
$ rake test test/models/
|
315
|
+
$ bin/rake test test/models/article_test.rb test_should_not_save_article_without_title
|
305
316
|
.
|
306
317
|
|
307
318
|
Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s.
|
@@ -326,15 +337,15 @@ end
|
|
326
337
|
Now you can see even more output in the console from running the tests:
|
327
338
|
|
328
339
|
```bash
|
329
|
-
$ rake test test/models/
|
340
|
+
$ bin/rake test test/models/article_test.rb test_should_report_error
|
330
341
|
E
|
331
342
|
|
332
343
|
Finished tests in 0.030974s, 32.2851 tests/s, 0.0000 assertions/s.
|
333
344
|
|
334
345
|
1) Error:
|
335
|
-
test_should_report_error(
|
336
|
-
NameError: undefined local variable or method `some_undefined_variable' for #<
|
337
|
-
test/models/
|
346
|
+
test_should_report_error(ArticleTest):
|
347
|
+
NameError: undefined local variable or method `some_undefined_variable' for #<ArticleTest:0x007fe32e24afe0>
|
348
|
+
test/models/article_test.rb:10:in `block in <class:ArticleTest>'
|
338
349
|
|
339
350
|
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
|
340
351
|
```
|
@@ -343,6 +354,17 @@ Notice the 'E' in the output. It denotes a test with error.
|
|
343
354
|
|
344
355
|
NOTE: The execution of each test method stops as soon as any error or an assertion failure is encountered, and the test suite continues with the next method. All test methods are executed in alphabetical order.
|
345
356
|
|
357
|
+
When a test fails you are presented with the corresponding backtrace. By default
|
358
|
+
Rails filters that backtrace and will only print lines relevant to your
|
359
|
+
application. This eliminates the framework noise and helps to focus on your
|
360
|
+
code. However there are situations when you want to see the full
|
361
|
+
backtrace. simply set the `BACKTRACE` environment variable to enable this
|
362
|
+
behavior:
|
363
|
+
|
364
|
+
```bash
|
365
|
+
$ BACKTRACE=1 bin/rake test test/models/article_test.rb
|
366
|
+
```
|
367
|
+
|
346
368
|
### What to Include in Your Unit Tests
|
347
369
|
|
348
370
|
Ideally, you would like to include a test for everything which could possibly break. It's a good practice to have at least one test for each of your validations and at least one test for every method in your model.
|
@@ -352,43 +374,51 @@ Ideally, you would like to include a test for everything which could possibly br
|
|
352
374
|
By now you've caught a glimpse of some of the assertions that are available. Assertions are the worker bees of testing. They are the ones that actually perform the checks to ensure that things are going as planned.
|
353
375
|
|
354
376
|
There are a bunch of different types of assertions you can use.
|
355
|
-
Here's an extract of the assertions you can use with `minitest
|
377
|
+
Here's an extract of the assertions you can use with [`Minitest`](https://github.com/seattlerb/minitest), the default testing library used by Rails. The `[msg]` parameter is an optional string message you can specify to make your test failure messages clearer. It's not required.
|
356
378
|
|
357
379
|
| Assertion | Purpose |
|
358
380
|
| ---------------------------------------------------------------- | ------- |
|
359
381
|
| `assert( test, [msg] )` | Ensures that `test` is true.|
|
360
|
-
| `
|
382
|
+
| `assert_not( test, [msg] )` | Ensures that `test` is false.|
|
361
383
|
| `assert_equal( expected, actual, [msg] )` | Ensures that `expected == actual` is true.|
|
362
|
-
| `
|
384
|
+
| `assert_not_equal( expected, actual, [msg] )` | Ensures that `expected != actual` is true.|
|
363
385
|
| `assert_same( expected, actual, [msg] )` | Ensures that `expected.equal?(actual)` is true.|
|
364
|
-
| `
|
386
|
+
| `assert_not_same( expected, actual, [msg] )` | Ensures that `expected.equal?(actual)` is false.|
|
365
387
|
| `assert_nil( obj, [msg] )` | Ensures that `obj.nil?` is true.|
|
366
|
-
| `
|
388
|
+
| `assert_not_nil( obj, [msg] )` | Ensures that `obj.nil?` is false.|
|
389
|
+
| `assert_empty( obj, [msg] )` | Ensures that `obj` is `empty?`.|
|
390
|
+
| `assert_not_empty( obj, [msg] )` | Ensures that `obj` is not `empty?`.|
|
367
391
|
| `assert_match( regexp, string, [msg] )` | Ensures that a string matches the regular expression.|
|
368
|
-
| `
|
392
|
+
| `assert_no_match( regexp, string, [msg] )` | Ensures that a string doesn't match the regular expression.|
|
393
|
+
| `assert_includes( collection, obj, [msg] )` | Ensures that `obj` is in `collection`.|
|
394
|
+
| `assert_not_includes( collection, obj, [msg] )` | Ensures that `obj` is not in `collection`.|
|
369
395
|
| `assert_in_delta( expecting, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are within `delta` of each other.|
|
370
|
-
| `
|
396
|
+
| `assert_not_in_delta( expecting, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.|
|
371
397
|
| `assert_throws( symbol, [msg] ) { block }` | Ensures that the given block throws the symbol.|
|
372
398
|
| `assert_raises( exception1, exception2, ... ) { block }` | Ensures that the given block raises one of the given exceptions.|
|
373
399
|
| `assert_nothing_raised( exception1, exception2, ... ) { block }` | Ensures that the given block doesn't raise one of the given exceptions.|
|
374
400
|
| `assert_instance_of( class, obj, [msg] )` | Ensures that `obj` is an instance of `class`.|
|
375
|
-
| `
|
401
|
+
| `assert_not_instance_of( class, obj, [msg] )` | Ensures that `obj` is not an instance of `class`.|
|
376
402
|
| `assert_kind_of( class, obj, [msg] )` | Ensures that `obj` is or descends from `class`.|
|
377
|
-
| `
|
403
|
+
| `assert_not_kind_of( class, obj, [msg] )` | Ensures that `obj` is not an instance of `class` and is not descending from it.|
|
378
404
|
| `assert_respond_to( obj, symbol, [msg] )` | Ensures that `obj` responds to `symbol`.|
|
379
|
-
| `
|
405
|
+
| `assert_not_respond_to( obj, symbol, [msg] )` | Ensures that `obj` does not respond to `symbol`.|
|
380
406
|
| `assert_operator( obj1, operator, [obj2], [msg] )` | Ensures that `obj1.operator(obj2)` is true.|
|
381
|
-
| `
|
407
|
+
| `assert_not_operator( obj1, operator, [obj2], [msg] )` | Ensures that `obj1.operator(obj2)` is false.|
|
408
|
+
| `assert_predicate ( obj, predicate, [msg] )` | Ensures that `obj.predicate` is true, e.g. `assert_predicate str, :empty?`|
|
409
|
+
| `assert_not_predicate ( obj, predicate, [msg] )` | Ensures that `obj.predicate` is false, e.g. `assert_not_predicate str, :empty?`|
|
382
410
|
| `assert_send( array, [msg] )` | Ensures that executing the method listed in `array[1]` on the object in `array[0]` with the parameters of `array[2 and up]` is true. This one is weird eh?|
|
383
411
|
| `flunk( [msg] )` | Ensures failure. This is useful to explicitly mark a test that isn't finished yet.|
|
384
412
|
|
413
|
+
The above are subset of assertions that minitest supports. For an exhaustive & more up-to-date list, please check [Minitest API documentation](http://docs.seattlerb.org/minitest/), specifically [`Minitest::Assertions`](http://docs.seattlerb.org/minitest/Minitest/Assertions.html)
|
414
|
+
|
385
415
|
Because of the modular nature of the testing framework, it is possible to create your own assertions. In fact, that's exactly what Rails does. It includes some specialized assertions to make your life easier.
|
386
416
|
|
387
417
|
NOTE: Creating your own assertions is an advanced topic that we won't cover in this tutorial.
|
388
418
|
|
389
419
|
### Rails Specific Assertions
|
390
420
|
|
391
|
-
Rails adds some custom assertions of its own to the `
|
421
|
+
Rails adds some custom assertions of its own to the `minitest` framework:
|
392
422
|
|
393
423
|
| Assertion | Purpose |
|
394
424
|
| --------------------------------------------------------------------------------- | ------- |
|
@@ -396,8 +426,8 @@ Rails adds some custom assertions of its own to the `test/unit` framework:
|
|
396
426
|
| `assert_no_difference(expressions, message = nil, &block)` | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.|
|
397
427
|
| `assert_recognizes(expected_options, path, extras={}, message=nil)` | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.|
|
398
428
|
| `assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)` | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.|
|
399
|
-
| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299,
|
400
|
-
| `assert_redirected_to(options = {}, message=nil)` | Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on
|
429
|
+
| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range. You can also pass an explicit status number or its symbolic equivalent. For more information, see [full list of status codes](http://rubydoc.info/github/rack/rack/master/Rack/Utils#HTTP_STATUS_CODES-constant) and how their [mapping](http://rubydoc.info/github/rack/rack/master/Rack/Utils#SYMBOL_TO_STATUS_CODE-constant) works.|
|
430
|
+
| `assert_redirected_to(options = {}, message=nil)` | Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on. You can also pass named routes such as `assert_redirected_to root_path` and Active Record objects such as `assert_redirected_to @article`.|
|
401
431
|
| `assert_template(expected = nil, message=nil)` | Asserts that the request was rendered with the appropriate template file.|
|
402
432
|
|
403
433
|
You'll see the usage of some of these assertions in the next chapter.
|
@@ -417,24 +447,26 @@ You should test for things such as:
|
|
417
447
|
* was the correct object stored in the response template?
|
418
448
|
* was the appropriate message displayed to the user in the view?
|
419
449
|
|
420
|
-
Now that we have used Rails scaffold generator for our `
|
450
|
+
Now that we have used Rails scaffold generator for our `Article` resource, it has already created the controller code and tests. You can take look at the file `articles_controller_test.rb` in the `test/controllers` directory.
|
421
451
|
|
422
|
-
Let me take you through one such test, `test_should_get_index` from the file `
|
452
|
+
Let me take you through one such test, `test_should_get_index` from the file `articles_controller_test.rb`.
|
423
453
|
|
424
454
|
```ruby
|
425
|
-
|
426
|
-
get
|
427
|
-
|
428
|
-
|
455
|
+
class ArticlesControllerTest < ActionController::TestCase
|
456
|
+
test "should get index" do
|
457
|
+
get :index
|
458
|
+
assert_response :success
|
459
|
+
assert_not_nil assigns(:articles)
|
460
|
+
end
|
429
461
|
end
|
430
462
|
```
|
431
463
|
|
432
|
-
In the `test_should_get_index` test, Rails simulates a request on the action called `index`, making sure the request was successful and also ensuring that it assigns a valid `
|
464
|
+
In the `test_should_get_index` test, Rails simulates a request on the action called `index`, making sure the request was successful and also ensuring that it assigns a valid `articles` instance variable.
|
433
465
|
|
434
466
|
The `get` method kicks off the web request and populates the results into the response. It accepts 4 arguments:
|
435
467
|
|
436
468
|
* The action of the controller you are requesting. This can be in the form of a string or a symbol.
|
437
|
-
* An optional hash of request parameters to pass into the action (eg. query string parameters or
|
469
|
+
* An optional hash of request parameters to pass into the action (eg. query string parameters or article variables).
|
438
470
|
* An optional hash of session variables to pass along with the request.
|
439
471
|
* An optional hash of flash values.
|
440
472
|
|
@@ -450,17 +482,17 @@ Another example: Calling the `:view` action, passing an `id` of 12 as the `param
|
|
450
482
|
get(:view, {'id' => '12'}, nil, {'message' => 'booya!'})
|
451
483
|
```
|
452
484
|
|
453
|
-
NOTE: If you try running `
|
485
|
+
NOTE: If you try running `test_should_create_article` test from `articles_controller_test.rb` it will fail on account of the newly added model level validation and rightly so.
|
454
486
|
|
455
|
-
Let us modify `
|
487
|
+
Let us modify `test_should_create_article` test in `articles_controller_test.rb` so that all our test pass:
|
456
488
|
|
457
489
|
```ruby
|
458
|
-
test "should create
|
459
|
-
assert_difference('
|
460
|
-
post :create,
|
490
|
+
test "should create article" do
|
491
|
+
assert_difference('Article.count') do
|
492
|
+
post :create, article: {title: 'Some title'}
|
461
493
|
end
|
462
494
|
|
463
|
-
assert_redirected_to
|
495
|
+
assert_redirected_to article_path(assigns(:article))
|
464
496
|
end
|
465
497
|
```
|
466
498
|
|
@@ -511,12 +543,14 @@ You also have access to three instance variables in your functional tests:
|
|
511
543
|
|
512
544
|
### Setting Headers and CGI variables
|
513
545
|
|
514
|
-
|
515
|
-
|
546
|
+
[HTTP headers](http://tools.ietf.org/search/rfc2616#section-5.3)
|
547
|
+
and
|
548
|
+
[CGI variables](http://tools.ietf.org/search/rfc3875#section-4.1)
|
549
|
+
can be set directly on the `@request` instance variable:
|
516
550
|
|
517
551
|
```ruby
|
518
552
|
# setting a HTTP Header
|
519
|
-
@request.headers["
|
553
|
+
@request.headers["Accept"] = "text/plain, text/html"
|
520
554
|
get :index # simulate the request with custom header
|
521
555
|
|
522
556
|
# setting a CGI variable
|
@@ -567,12 +601,12 @@ is the correct way to assert for the layout when the view renders a partial with
|
|
567
601
|
Here's another example that uses `flash`, `assert_redirected_to`, and `assert_difference`:
|
568
602
|
|
569
603
|
```ruby
|
570
|
-
test "should create
|
571
|
-
assert_difference('
|
572
|
-
post :create,
|
604
|
+
test "should create article" do
|
605
|
+
assert_difference('Article.count') do
|
606
|
+
post :create, article: {title: 'Hi', body: 'This is my first article.'}
|
573
607
|
end
|
574
|
-
assert_redirected_to
|
575
|
-
assert_equal '
|
608
|
+
assert_redirected_to article_path(assigns(:article))
|
609
|
+
assert_equal 'Article was successfully created.', flash[:notice]
|
576
610
|
end
|
577
611
|
```
|
578
612
|
|
@@ -580,13 +614,13 @@ end
|
|
580
614
|
|
581
615
|
Testing the response to your request by asserting the presence of key HTML elements and their content is a useful way to test the views of your application. The `assert_select` assertion allows you to do this by using a simple yet powerful syntax.
|
582
616
|
|
583
|
-
NOTE: You may find references to `assert_tag` in other documentation
|
617
|
+
NOTE: You may find references to `assert_tag` in other documentation. This has been removed in 4.2. Use `assert_select` instead.
|
584
618
|
|
585
619
|
There are two forms of `assert_select`:
|
586
620
|
|
587
|
-
`assert_select(selector, [equality], [message])` ensures that the equality condition is met on the selected elements through the selector. The selector may be a CSS selector expression (String)
|
621
|
+
`assert_select(selector, [equality], [message])` ensures that the equality condition is met on the selected elements through the selector. The selector may be a CSS selector expression (String) or an expression with substitution values.
|
588
622
|
|
589
|
-
`assert_select(element, selector, [equality], [message])` ensures that the equality condition is met on all the selected elements through the selector starting from the _element_ (instance of `
|
623
|
+
`assert_select(element, selector, [equality], [message])` ensures that the equality condition is met on all the selected elements through the selector starting from the _element_ (instance of `Nokogiri::XML::Node` or `Nokogiri::XML::NodeSet`) and its descendants.
|
590
624
|
|
591
625
|
For example, you could verify the contents on the title element in your response with:
|
592
626
|
|
@@ -616,17 +650,17 @@ assert_select "ol" do
|
|
616
650
|
end
|
617
651
|
```
|
618
652
|
|
619
|
-
The `assert_select` assertion is quite powerful. For more advanced usage, refer to its [documentation](
|
653
|
+
The `assert_select` assertion is quite powerful. For more advanced usage, refer to its [documentation](https://github.com/rails/rails-dom-testing/blob/master/lib/rails/dom/testing/assertions/selector_assertions.rb).
|
620
654
|
|
621
655
|
#### Additional View-Based Assertions
|
622
656
|
|
623
657
|
There are more assertions that are primarily used in testing views:
|
624
658
|
|
625
|
-
| Assertion
|
626
|
-
|
|
627
|
-
| `assert_select_email`
|
628
|
-
| `assert_select_encoded`
|
629
|
-
| `css_select(selector)`
|
659
|
+
| Assertion | Purpose |
|
660
|
+
| --------------------------------------------------------- | ------- |
|
661
|
+
| `assert_select_email` | Allows you to make assertions on the body of an e-mail. |
|
662
|
+
| `assert_select_encoded` | Allows you to make assertions on encoded HTML. It does this by un-encoding the contents of each element and then calling the block with all the un-encoded elements.|
|
663
|
+
| `css_select(selector)` or `css_select(element, selector)` | Returns an array of all the elements selected by the _selector_. In the second variant it first matches the base _element_ and tries to match the _selector_ expression on any of its children. If there are no matches both variants return an empty array.|
|
630
664
|
|
631
665
|
Here's an example of using `assert_select_email`:
|
632
666
|
|
@@ -644,7 +678,7 @@ Integration tests are used to test the interaction among any number of controlle
|
|
644
678
|
Unlike Unit and Functional tests, integration tests have to be explicitly created under the 'test/integration' folder within your application. Rails provides a generator to create an integration test skeleton for you.
|
645
679
|
|
646
680
|
```bash
|
647
|
-
$ rails generate integration_test user_flows
|
681
|
+
$ bin/rails generate integration_test user_flows
|
648
682
|
exists test/integration/
|
649
683
|
create test/integration/user_flows_test.rb
|
650
684
|
```
|
@@ -690,8 +724,6 @@ A simple integration test that exercises multiple controllers:
|
|
690
724
|
require 'test_helper'
|
691
725
|
|
692
726
|
class UserFlowsTest < ActionDispatch::IntegrationTest
|
693
|
-
fixtures :users
|
694
|
-
|
695
727
|
test "login and browse site" do
|
696
728
|
# login via https
|
697
729
|
https!
|
@@ -703,9 +735,9 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
703
735
|
assert_equal 'Welcome david!', flash[:notice]
|
704
736
|
|
705
737
|
https!(false)
|
706
|
-
get "/
|
738
|
+
get "/articles/all"
|
707
739
|
assert_response :success
|
708
|
-
assert assigns(:
|
740
|
+
assert assigns(:articles)
|
709
741
|
end
|
710
742
|
end
|
711
743
|
```
|
@@ -718,10 +750,7 @@ Here's an example of multiple sessions and custom DSL in an integration test
|
|
718
750
|
require 'test_helper'
|
719
751
|
|
720
752
|
class UserFlowsTest < ActionDispatch::IntegrationTest
|
721
|
-
fixtures :users
|
722
|
-
|
723
753
|
test "login and browse site" do
|
724
|
-
|
725
754
|
# User david logs in
|
726
755
|
david = login(:david)
|
727
756
|
# User guest logs in
|
@@ -741,102 +770,95 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
741
770
|
|
742
771
|
private
|
743
772
|
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
773
|
+
module CustomDsl
|
774
|
+
def browses_site
|
775
|
+
get "/products/all"
|
776
|
+
assert_response :success
|
777
|
+
assert assigns(:products)
|
778
|
+
end
|
749
779
|
end
|
750
|
-
end
|
751
780
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
781
|
+
def login(user)
|
782
|
+
open_session do |sess|
|
783
|
+
sess.extend(CustomDsl)
|
784
|
+
u = users(user)
|
785
|
+
sess.https!
|
786
|
+
sess.post "/login", username: u.username, password: u.password
|
787
|
+
assert_equal '/welcome', sess.path
|
788
|
+
sess.https!(false)
|
789
|
+
end
|
760
790
|
end
|
761
|
-
end
|
762
791
|
end
|
763
792
|
```
|
764
793
|
|
765
794
|
Rake Tasks for Running your Tests
|
766
795
|
---------------------------------
|
767
796
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
|
773
|
-
|
|
774
|
-
| `rake test
|
775
|
-
| `rake test:
|
776
|
-
| `rake test:
|
777
|
-
| `rake test:
|
778
|
-
| `rake test:
|
779
|
-
| `rake test:
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
|
788
|
-
|
789
|
-
Brief Note About `MiniTest`
|
797
|
+
Rails comes with a number of built-in rake tasks to help with testing. The
|
798
|
+
table below lists the commands included in the default Rakefile when a Rails
|
799
|
+
project is created.
|
800
|
+
|
801
|
+
| Tasks | Description |
|
802
|
+
| ----------------------- | ----------- |
|
803
|
+
| `rake test` | Runs all tests in the `test` folder. You can also simply run `rake` as Rails will run all the tests by default |
|
804
|
+
| `rake test:controllers` | Runs all the controller tests from `test/controllers` |
|
805
|
+
| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional` |
|
806
|
+
| `rake test:helpers` | Runs all the helper tests from `test/helpers` |
|
807
|
+
| `rake test:integration` | Runs all the integration tests from `test/integration` |
|
808
|
+
| `rake test:jobs` | Runs all the job tests from `test/jobs` |
|
809
|
+
| `rake test:mailers` | Runs all the mailer tests from `test/mailers` |
|
810
|
+
| `rake test:models` | Runs all the model tests from `test/models` |
|
811
|
+
| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit` |
|
812
|
+
| `rake test:db` | Runs all tests in the `test` folder and resets the db |
|
813
|
+
|
814
|
+
|
815
|
+
A Brief Note About Minitest
|
790
816
|
-----------------------------
|
791
817
|
|
792
|
-
Ruby ships with a
|
793
|
-
us to use all of the basic assertions in our tests.
|
818
|
+
Ruby ships with a vast Standard Library for all common use-cases including testing. Since version 1.9, Ruby provides `Minitest`, a framework for testing. All the basic assertions such as `assert_equal` discussed above are actually defined in `Minitest::Assertions`. The classes `ActiveSupport::TestCase`, `ActionController::TestCase`, `ActionMailer::TestCase`, `ActionView::TestCase` and `ActionDispatch::IntegrationTest` - which we have been inheriting in our test classes - include `Minitest::Assertions`, allowing us to use all of the basic assertions in our tests.
|
794
819
|
|
795
|
-
|
796
|
-
|
797
|
-
NOTE: For more information on `Test::Unit`, refer to [test/unit Documentation](http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/)
|
798
|
-
For more information on `MiniTest`, refer to [Minitest](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/minitest/unit/rdoc/)
|
820
|
+
NOTE: For more information on `Minitest`, refer to [Minitest](http://ruby-doc.org/stdlib-2.1.0/libdoc/minitest/rdoc/MiniTest.html)
|
799
821
|
|
800
822
|
Setup and Teardown
|
801
823
|
------------------
|
802
824
|
|
803
|
-
If you would like to run a block of code before the start of each test and another block of code after the end of each test you have two special callbacks for your rescue. Let's take note of this by looking at an example for our functional test in `
|
825
|
+
If you would like to run a block of code before the start of each test and another block of code after the end of each test you have two special callbacks for your rescue. Let's take note of this by looking at an example for our functional test in `Articles` controller:
|
804
826
|
|
805
827
|
```ruby
|
806
828
|
require 'test_helper'
|
807
829
|
|
808
|
-
class
|
830
|
+
class ArticlesControllerTest < ActionController::TestCase
|
809
831
|
|
810
832
|
# called before every single test
|
811
833
|
def setup
|
812
|
-
@
|
834
|
+
@article = articles(:one)
|
813
835
|
end
|
814
836
|
|
815
837
|
# called after every single test
|
816
838
|
def teardown
|
817
|
-
# as we are re-initializing @
|
839
|
+
# as we are re-initializing @article before every test
|
818
840
|
# setting it to nil here is not essential but I hope
|
819
841
|
# you understand how you can use the teardown method
|
820
|
-
@
|
842
|
+
@article = nil
|
821
843
|
end
|
822
844
|
|
823
|
-
test "should show
|
824
|
-
get :show, id: @
|
845
|
+
test "should show article" do
|
846
|
+
get :show, id: @article.id
|
825
847
|
assert_response :success
|
826
848
|
end
|
827
849
|
|
828
|
-
test "should destroy
|
829
|
-
assert_difference('
|
830
|
-
delete :destroy, id: @
|
850
|
+
test "should destroy article" do
|
851
|
+
assert_difference('Article.count', -1) do
|
852
|
+
delete :destroy, id: @article.id
|
831
853
|
end
|
832
854
|
|
833
|
-
assert_redirected_to
|
855
|
+
assert_redirected_to articles_path
|
834
856
|
end
|
835
857
|
|
836
858
|
end
|
837
859
|
```
|
838
860
|
|
839
|
-
Above, the `setup` method is called before each test and so `@
|
861
|
+
Above, the `setup` method is called before each test and so `@article` is available for each of the tests. Rails implements `setup` and `teardown` as `ActiveSupport::Callbacks`. Which essentially means you need not only use `setup` and `teardown` as methods in your tests. You could specify them by using:
|
840
862
|
|
841
863
|
* a block
|
842
864
|
* a method (like in the earlier example)
|
@@ -848,51 +870,56 @@ Let's see the earlier example by specifying `setup` callback by specifying a met
|
|
848
870
|
```ruby
|
849
871
|
require 'test_helper'
|
850
872
|
|
851
|
-
class
|
873
|
+
class ArticlesControllerTest < ActionController::TestCase
|
852
874
|
|
853
875
|
# called before every single test
|
854
|
-
setup :
|
876
|
+
setup :initialize_article
|
855
877
|
|
856
878
|
# called after every single test
|
857
879
|
def teardown
|
858
|
-
@
|
880
|
+
@article = nil
|
859
881
|
end
|
860
882
|
|
861
|
-
test "should show
|
862
|
-
get :show, id: @
|
883
|
+
test "should show article" do
|
884
|
+
get :show, id: @article.id
|
863
885
|
assert_response :success
|
864
886
|
end
|
865
887
|
|
866
|
-
test "should update
|
867
|
-
patch :update, id: @
|
868
|
-
assert_redirected_to
|
888
|
+
test "should update article" do
|
889
|
+
patch :update, id: @article.id, article: {}
|
890
|
+
assert_redirected_to article_path(assigns(:article))
|
869
891
|
end
|
870
892
|
|
871
|
-
test "should destroy
|
872
|
-
assert_difference('
|
873
|
-
delete :destroy, id: @
|
893
|
+
test "should destroy article" do
|
894
|
+
assert_difference('Article.count', -1) do
|
895
|
+
delete :destroy, id: @article.id
|
874
896
|
end
|
875
897
|
|
876
|
-
assert_redirected_to
|
898
|
+
assert_redirected_to articles_path
|
877
899
|
end
|
878
900
|
|
879
901
|
private
|
880
902
|
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
903
|
+
def initialize_article
|
904
|
+
@article = articles(:one)
|
905
|
+
end
|
885
906
|
end
|
886
907
|
```
|
887
908
|
|
888
909
|
Testing Routes
|
889
910
|
--------------
|
890
911
|
|
891
|
-
Like everything else in your Rails application, it is recommended that you test your routes.
|
912
|
+
Like everything else in your Rails application, it is recommended that you test your routes. Below are example tests for the routes of default `show` and `create` action of `Articles` controller above and it should look like:
|
892
913
|
|
893
914
|
```ruby
|
894
|
-
|
895
|
-
|
915
|
+
class ArticleRoutesTest < ActionController::TestCase
|
916
|
+
test "should route to article" do
|
917
|
+
assert_routing '/articles/1', { controller: "articles", action: "show", id: "1" }
|
918
|
+
end
|
919
|
+
|
920
|
+
test "should route to create article" do
|
921
|
+
assert_routing({ method: 'post', path: '/articles' }, { controller: "articles", action: "create" })
|
922
|
+
end
|
896
923
|
end
|
897
924
|
```
|
898
925
|
|
@@ -903,7 +930,7 @@ Testing mailer classes requires some specific tools to do a thorough job.
|
|
903
930
|
|
904
931
|
### Keeping the Postman in Check
|
905
932
|
|
906
|
-
Your mailer classes
|
933
|
+
Your mailer classes - like every other part of your Rails application - should be tested to ensure that it is working as expected.
|
907
934
|
|
908
935
|
The goals of testing your mailer classes are to ensure that:
|
909
936
|
|
@@ -923,7 +950,7 @@ In order to test that your mailer is working as expected, you can use unit tests
|
|
923
950
|
|
924
951
|
For the purposes of unit testing a mailer, fixtures are used to provide an example of how the output _should_ look. Because these are example emails, and not Active Record data like the other fixtures, they are kept in their own subdirectory apart from the other fixtures. The name of the directory within `test/fixtures` directly corresponds to the name of the mailer. So, for a mailer named `UserMailer`, the fixtures should reside in `test/fixtures/user_mailer` directory.
|
925
952
|
|
926
|
-
|
953
|
+
If you generated your mailer, the generator does not create stub fixtures for the mailers actions. You'll have to create those files yourself as described above.
|
927
954
|
|
928
955
|
#### The Basic Test Case
|
929
956
|
|
@@ -933,12 +960,11 @@ Here's a unit test to test a mailer named `UserMailer` whose action `invite` is
|
|
933
960
|
require 'test_helper'
|
934
961
|
|
935
962
|
class UserMailerTest < ActionMailer::TestCase
|
936
|
-
tests UserMailer
|
937
963
|
test "invite" do
|
938
964
|
# Send the email, then test that it got queued
|
939
965
|
email = UserMailer.create_invite('me@example.com',
|
940
|
-
'friend@example.com', Time.now).
|
941
|
-
|
966
|
+
'friend@example.com', Time.now).deliver_now
|
967
|
+
assert_not ActionMailer::Base.deliveries.empty?
|
942
968
|
|
943
969
|
# Test the body of the sent email contains what we expect it to
|
944
970
|
assert_equal ['me@example.com'], email.from
|
@@ -992,7 +1018,102 @@ class UserControllerTest < ActionController::TestCase
|
|
992
1018
|
|
993
1019
|
assert_equal "You have been invited by me@example.com", invite_email.subject
|
994
1020
|
assert_equal 'friend@example.com', invite_email.to[0]
|
995
|
-
assert_match(/Hi friend@example.com/, invite_email.body)
|
1021
|
+
assert_match(/Hi friend@example.com/, invite_email.body.to_s)
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
```
|
1025
|
+
|
1026
|
+
Testing helpers
|
1027
|
+
---------------
|
1028
|
+
|
1029
|
+
In order to test helpers, all you need to do is check that the output of the
|
1030
|
+
helper method matches what you'd expect. Tests related to the helpers are
|
1031
|
+
located under the `test/helpers` directory.
|
1032
|
+
|
1033
|
+
A helper test looks like so:
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
require 'test_helper'
|
1037
|
+
|
1038
|
+
class UserHelperTest < ActionView::TestCase
|
1039
|
+
end
|
1040
|
+
```
|
1041
|
+
|
1042
|
+
A helper is just a simple module where you can define methods which are
|
1043
|
+
available into your views. To test the output of the helper's methods, you just
|
1044
|
+
have to use a mixin like this:
|
1045
|
+
|
1046
|
+
```ruby
|
1047
|
+
class UserHelperTest < ActionView::TestCase
|
1048
|
+
include UserHelper
|
1049
|
+
|
1050
|
+
test "should return the user name" do
|
1051
|
+
# ...
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
```
|
1055
|
+
|
1056
|
+
Moreover, since the test class extends from `ActionView::TestCase`, you have
|
1057
|
+
access to Rails' helper methods such as `link_to` or `pluralize`.
|
1058
|
+
|
1059
|
+
Testing Jobs
|
1060
|
+
------------
|
1061
|
+
|
1062
|
+
Since your custom jobs can be queued at different levels inside your application,
|
1063
|
+
you'll need to test both jobs themselves (their behavior when they get enqueued)
|
1064
|
+
and that other entities correctly enqueue them.
|
1065
|
+
|
1066
|
+
### A Basic Test Case
|
1067
|
+
|
1068
|
+
By default, when you generate a job, an associated test will be generated as well
|
1069
|
+
under the `test/jobs` directory. Here's an example test with a billing job:
|
1070
|
+
|
1071
|
+
```ruby
|
1072
|
+
require 'test_helper'
|
1073
|
+
|
1074
|
+
class BillingJobTest < ActiveJob::TestCase
|
1075
|
+
test 'that account is charged' do
|
1076
|
+
BillingJob.perform_now(account, product)
|
1077
|
+
assert account.reload.charged_for?(product)
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
```
|
1081
|
+
|
1082
|
+
This test is pretty simple and only asserts that the job get the work done
|
1083
|
+
as expected.
|
1084
|
+
|
1085
|
+
By default, `ActiveJob::TestCase` will set the queue adapter to `:test` so that
|
1086
|
+
your jobs are performed inline. It will also ensure that all previously performed
|
1087
|
+
and enqueued jobs are cleared before any test run so you can safely assume that
|
1088
|
+
no jobs have already been executed in the scope of each test.
|
1089
|
+
|
1090
|
+
### Custom Assertions And Testing Jobs Inside Other Components
|
1091
|
+
|
1092
|
+
Active Job ships with a bunch of custom assertions that can be used to lessen
|
1093
|
+
the verbosity of tests:
|
1094
|
+
|
1095
|
+
| Assertion | Purpose |
|
1096
|
+
| -------------------------------------- | ------- |
|
1097
|
+
| `assert_enqueued_jobs(number)` | Asserts that the number of enqueued jobs matches the given number. |
|
1098
|
+
| `assert_performed_jobs(number)` | Asserts that the number of performed jobs matches the given number. |
|
1099
|
+
| `assert_no_enqueued_jobs { ... }` | Asserts that no jobs have been enqueued. |
|
1100
|
+
| `assert_no_performed_jobs { ... }` | Asserts that no jobs have been performed. |
|
1101
|
+
| `assert_enqueued_with([args]) { ... }` | Asserts that the job passed in the block has been enqueued with the given arguments. |
|
1102
|
+
| `assert_performed_with([args]) { ... }`| Asserts that the job passed in the block has been performed with the given arguments. |
|
1103
|
+
|
1104
|
+
It's a good practice to ensure that your jobs correctly get enqueued or performed
|
1105
|
+
wherever you invoke them (e.g. inside your controllers). This is precisely where
|
1106
|
+
the custom assertions provided by Active Job are pretty useful. For instance,
|
1107
|
+
within a model:
|
1108
|
+
|
1109
|
+
```ruby
|
1110
|
+
require 'test_helper'
|
1111
|
+
|
1112
|
+
class ProductTest < ActiveJob::TestCase
|
1113
|
+
test 'billing job scheduling' do
|
1114
|
+
assert_enqueued_with(job: BillingJob) do
|
1115
|
+
product.charge(account)
|
1116
|
+
end
|
996
1117
|
end
|
997
1118
|
end
|
998
1119
|
```
|
@@ -1000,11 +1121,12 @@ end
|
|
1000
1121
|
Other Testing Approaches
|
1001
1122
|
------------------------
|
1002
1123
|
|
1003
|
-
The built-in `
|
1124
|
+
The built-in `minitest` based testing is not the only way to test Rails applications. Rails developers have come up with a wide variety of other approaches and aids for testing, including:
|
1004
1125
|
|
1005
1126
|
* [NullDB](http://avdi.org/projects/nulldb/), a way to speed up testing by avoiding database use.
|
1006
1127
|
* [Factory Girl](https://github.com/thoughtbot/factory_girl/tree/master), a replacement for fixtures.
|
1007
|
-
* [
|
1128
|
+
* [Fixture Builder](https://github.com/rdy/fixture_builder), a tool that compiles Ruby factories into fixtures before a test run.
|
1008
1129
|
* [MiniTest::Spec Rails](https://github.com/metaskills/minitest-spec-rails), use the MiniTest::Spec DSL within your rails tests.
|
1009
1130
|
* [Shoulda](http://www.thoughtbot.com/projects/shoulda), an extension to `test/unit` with additional helpers, macros, and assertions.
|
1010
1131
|
* [RSpec](http://relishapp.com/rspec), a behavior-driven development framework
|
1132
|
+
* [Capybara](http://jnicklas.github.com/capybara/), Acceptance test framework for web applications
|