ZenTest 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +16 -4
- data/Manifest.txt +13 -0
- data/README.txt +19 -46
- data/Rakefile +31 -14
- data/bin/rails_test_audit +80 -0
- data/bin/unit_diff +4 -6
- data/lib/autotest.rb +22 -10
- data/lib/rails_autotest.rb +67 -15
- data/lib/test/rails.rb +267 -0
- data/lib/test/rails/controller_test_case.rb +357 -0
- data/lib/test/rails/functional_test_case.rb +64 -0
- data/lib/test/rails/ivar_proxy.rb +31 -0
- data/lib/test/rails/rake_tasks.rb +49 -0
- data/lib/test/rails/test_case.rb +12 -0
- data/lib/test/rails/view_test_case.rb +431 -0
- data/lib/test/zentest_assertions.rb +46 -0
- data/lib/zentest.rb +48 -2
- data/test/data/normal/test/#test_photo.rb# +0 -0
- data/test/data/rails/app/views/route/index.rhtml +0 -0
- data/test/data/rails/test/controllers/route_controller_test.rb +0 -0
- data/test/data/rails/test/views/route_view_test.rb +0 -0
- data/test/test_autotest.rb +9 -5
- data/test/test_rails_autotest.rb +142 -49
- metadata +30 -13
- data/bin/ZenTest +0 -28
data/lib/rails_autotest.rb
CHANGED
@@ -9,11 +9,13 @@ class RailsAutotest < Autotest
|
|
9
9
|
|
10
10
|
def initialize # :nodoc:
|
11
11
|
super
|
12
|
-
@exceptions = %r
|
12
|
+
@exceptions = %r%^\./(?:db|doc|log|public|script|vendor/rails)%
|
13
13
|
end
|
14
14
|
|
15
15
|
def map_file_names(updated) # :nodoc:
|
16
16
|
model_tests = []
|
17
|
+
controller_tests = []
|
18
|
+
view_tests = []
|
17
19
|
functional_tests = []
|
18
20
|
|
19
21
|
updated.each do |filename|
|
@@ -22,38 +24,86 @@ class RailsAutotest < Autotest
|
|
22
24
|
case filename
|
23
25
|
when %r%^test/fixtures/(.*)s.yml% then
|
24
26
|
model_tests << "test/unit/#{$1}_test.rb"
|
27
|
+
controller_tests << "test/controllers/#{$1}_controller_test.rb"
|
28
|
+
view_tests << "test/views/#{$1}_view_test.rb"
|
25
29
|
functional_tests << "test/functional/#{$1}_controller_test.rb"
|
26
30
|
when %r%^test/unit/.*rb$% then
|
27
31
|
model_tests << filename
|
28
32
|
when %r%^app/models/(.*)\.rb$% then
|
29
33
|
test_file = "test/unit/#{$1}_test.rb"
|
30
34
|
model_tests << test_file
|
35
|
+
when %r%^test/controllers/.*\.rb$% then
|
36
|
+
controller_tests << filename
|
37
|
+
when %r%^test/views/.*\.rb$% then
|
38
|
+
view_tests << filename
|
31
39
|
when %r%^test/functional/.*\.rb$% then
|
32
40
|
functional_tests << filename
|
33
41
|
when %r%^app/helpers/application_helper.rb% then
|
34
|
-
|
42
|
+
view_test_files = @files.keys.select do |f|
|
43
|
+
f =~ %r%^test/views/.*_test\.rb$%
|
44
|
+
end
|
45
|
+
functional_test_files = @files.keys.select do |f|
|
46
|
+
f =~ %r%^test/functional/.*_test\.rb$%
|
47
|
+
end
|
48
|
+
view_tests.push(*view_test_files.sort)
|
49
|
+
functional_tests.push(*functional_test_files.sort)
|
35
50
|
when %r%^app/helpers/(.*)_helper.rb% then
|
36
|
-
|
37
|
-
|
51
|
+
view_test_file = "test/views/#{$1}_view_test.rb"
|
52
|
+
view_tests << view_test_file
|
53
|
+
functional_test_file = "test/functional/#{$1}_controller_test.rb"
|
54
|
+
functional_tests << functional_test_file
|
38
55
|
when %r%^app/controllers/application.rb$% then
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
56
|
+
controller_test_file = "test/controllers/dummy_controller_test.rb"
|
57
|
+
controller_tests << controller_test_file
|
58
|
+
functional_test_file = "test/functional/dummy_controller_test.rb"
|
59
|
+
functional_tests << functional_test_file
|
60
|
+
when %r%^app/controllers/(.*)\.rb$% then
|
61
|
+
controller_test_file = "test/controllers/#{$1}_test.rb"
|
62
|
+
controller_tests << controller_test_file
|
63
|
+
functional_test_file = "test/functional/#{$1}_test.rb"
|
64
|
+
functional_tests << functional_test_file
|
44
65
|
when %r%^app/views/layouts/% then
|
66
|
+
view_test_file = "test/views/layouts_view_test.rb"
|
67
|
+
view_tests << view_test_file
|
45
68
|
when %r%^app/views/(.*)/% then
|
46
|
-
|
47
|
-
|
69
|
+
view_test_file = "test/views/#{$1}_view_test.rb"
|
70
|
+
view_tests << view_test_file
|
71
|
+
functional_test_file = "test/functional/#{$1}_controller_test.rb"
|
72
|
+
functional_tests << functional_test_file
|
48
73
|
when %r%^config/routes.rb$% then
|
49
|
-
|
74
|
+
functional_test_files = @files.keys.select do |f|
|
75
|
+
f =~ %r%^test/functional/.*_test\.rb$%
|
76
|
+
end
|
77
|
+
controller_test_files = @files.keys.select do |f|
|
78
|
+
f =~ %r%^test/controllers/.*_test\.rb$%
|
79
|
+
end
|
80
|
+
view_test_files = @files.keys.select do |f|
|
81
|
+
f =~ %r%^test/views/.*_test\.rb$%
|
82
|
+
end
|
83
|
+
controller_tests.push(*controller_test_files.sort)
|
84
|
+
view_tests.push(*view_test_files.sort)
|
85
|
+
functional_tests.push(*functional_test_files.sort)
|
50
86
|
when %r%^test/test_helper.rb$%,
|
51
87
|
%r%^config/boot.rb%,
|
52
88
|
%r%^config/database.yml%,
|
53
89
|
%r%^config/environment.rb%,
|
54
90
|
%r%^config/environments/test.rb% then
|
55
|
-
|
56
|
-
|
91
|
+
model_test_files = @files.keys.select do |f|
|
92
|
+
f =~ %r%^test/unit/.*_test\.rb$%
|
93
|
+
end
|
94
|
+
controller_test_files = @files.keys.select do |f|
|
95
|
+
f =~ %r%^test/controllers/.*_test\.rb$%
|
96
|
+
end
|
97
|
+
view_test_files = @files.keys.select do |f|
|
98
|
+
f =~ %r%^test/views/.*_test\.rb$%
|
99
|
+
end
|
100
|
+
functional_test_files = @files.keys.select do |f|
|
101
|
+
f =~ %r%^test/functional/.*_test\.rb$%
|
102
|
+
end
|
103
|
+
model_tests.push(*model_test_files.sort)
|
104
|
+
controller_tests.push(*controller_test_files.sort)
|
105
|
+
view_tests.push(*view_test_files.sort)
|
106
|
+
functional_tests.push(*functional_test_files.sort)
|
57
107
|
when %r%^vendor/%, /^Rakefile$/ then
|
58
108
|
# ignore standard rails files
|
59
109
|
else
|
@@ -62,9 +112,11 @@ class RailsAutotest < Autotest
|
|
62
112
|
end
|
63
113
|
|
64
114
|
model_tests = model_tests.uniq.select { |f| @files.has_key? f }
|
115
|
+
controller_tests = controller_tests.uniq.select { |f| @files.has_key? f }
|
116
|
+
view_tests = view_tests.uniq.select { |f| @files.has_key? f }
|
65
117
|
functional_tests = functional_tests.uniq.select { |f| @files.has_key? f }
|
66
118
|
|
67
|
-
return model_tests, functional_tests
|
119
|
+
return model_tests, controller_tests, view_tests, functional_tests
|
68
120
|
end
|
69
121
|
|
70
122
|
end
|
data/lib/test/rails.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test_help' # hopefully temporary, required for Test::Rails to work
|
3
|
+
# until we get rid of test_help so Test::Unit::TestCase
|
4
|
+
# is kept virgin.
|
5
|
+
|
6
|
+
$TESTING = true
|
7
|
+
|
8
|
+
##
|
9
|
+
# = Introduction
|
10
|
+
#
|
11
|
+
# Test::Rails helps you build industrial-strength Rails code by:
|
12
|
+
# * testing views separate from controllers
|
13
|
+
# * enhancing the assertion vocabulary, and
|
14
|
+
# * auditing your tests for consistency.
|
15
|
+
#
|
16
|
+
# = Details
|
17
|
+
#
|
18
|
+
# Test::Rails:
|
19
|
+
# * splits Functional test into Controller and View tests.
|
20
|
+
# * Splits view assertions away from controller assertions.
|
21
|
+
# * Helps decouple views from controllers.
|
22
|
+
# * Allows you to test AJAX actions in isolation.
|
23
|
+
# * Allows you to test a single partial.
|
24
|
+
# * Clearer failures when assert_tag fails.
|
25
|
+
# * An auditing script analyzes missing assertions in your controllers and
|
26
|
+
# views.
|
27
|
+
# * Library of assertions for testing views.
|
28
|
+
#
|
29
|
+
# = How to Convert to Test::Rails
|
30
|
+
#
|
31
|
+
# You will need to make three small changes to test/test_helper.rb to set up
|
32
|
+
# Test::Rails:
|
33
|
+
#
|
34
|
+
# First, add the following to 'test/test_helper.rb' before you require
|
35
|
+
# +test_help+:
|
36
|
+
#
|
37
|
+
# require 'test/rails'
|
38
|
+
#
|
39
|
+
# Next, change the class from "Unit" to "Rails" right after you
|
40
|
+
# require +test_help+. This prevents the bad things +test_help+ performs
|
41
|
+
# upon Test::Unit::TestCase.
|
42
|
+
#
|
43
|
+
# Your 'test/test_helper.rb' will end up looking like this:
|
44
|
+
#
|
45
|
+
# ENV["RAILS_ENV"] = "test"
|
46
|
+
# require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
47
|
+
# require 'test/rails'
|
48
|
+
# require 'test_help'
|
49
|
+
#
|
50
|
+
# class Test::Rails::TestCase
|
51
|
+
# ...
|
52
|
+
#
|
53
|
+
# Finally, you need to add the extra rake tasks Test::Rails provides.
|
54
|
+
# Add the following line to your Rakefile after you require
|
55
|
+
# 'tasks/rails':
|
56
|
+
#
|
57
|
+
# require 'test/rails/rake_tasks'
|
58
|
+
#
|
59
|
+
# *NOTE*:
|
60
|
+
#
|
61
|
+
# * get/post/etc. no longer have a session or flash argument. Use the session
|
62
|
+
# and flash accessor instead.
|
63
|
+
# * assert_tag will (eventually) not work in controller tests.
|
64
|
+
#
|
65
|
+
# == Writing View Tests
|
66
|
+
#
|
67
|
+
# View tests live in test/views. They are named after the controller that is
|
68
|
+
# being tested. For exampe, RouteViewTest will live in the file
|
69
|
+
# test/views/route_view_test.rb.
|
70
|
+
#
|
71
|
+
# === Example View Test Case
|
72
|
+
#
|
73
|
+
# require 'test/test_helper'
|
74
|
+
#
|
75
|
+
# # We are testing RouteController's views
|
76
|
+
# class RouteViewTest < Test::Rails::ViewTestCase
|
77
|
+
#
|
78
|
+
# fixtures :users, :routes, :points, :photos
|
79
|
+
#
|
80
|
+
# # testing the view for the delete action of RouteController
|
81
|
+
# def test_delete
|
82
|
+
# # Instance variables necessary for this view
|
83
|
+
# assigns[:loggedin_user] = users(:herbert)
|
84
|
+
# assigns[:route] = routes(:work)
|
85
|
+
#
|
86
|
+
# # render this view
|
87
|
+
# render
|
88
|
+
#
|
89
|
+
# # assert everything is as it should be
|
90
|
+
# assert_links_to "/route/flickr_refresh/#{routes(:work).id}"
|
91
|
+
#
|
92
|
+
# form_url = '/route/destroy'
|
93
|
+
# assert_post_form form_url
|
94
|
+
# assert_input form_url, :hidden, :id
|
95
|
+
# assert_submit form_url, 'Delete!'
|
96
|
+
# assert_links_to "/route/show/#{routes(:work).id}", 'No, I do not!'
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# # ...
|
100
|
+
#
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# All view tests are a subclass of Test::Rails::ViewTestCase. The name of the
|
104
|
+
# subclass must match the controller this view depends upon. ViewTestCase
|
105
|
+
# takes care of all the setup necessary for running the tests.
|
106
|
+
#
|
107
|
+
# The +test_delete+ method is named after the delete method in
|
108
|
+
# RouteController. The ViewTestCase#render method looks at the name of the
|
109
|
+
# test and tries to figure out which view file to use, so naming tests after
|
110
|
+
# actions will save you headaches and typing.
|
111
|
+
#
|
112
|
+
# Use +assigns+ to set up the variables the view will use when it renders.
|
113
|
+
#
|
114
|
+
# The call to render is the equivalent to a functional tests' get/post
|
115
|
+
# methods. It makes several assumptions, so be sure to read
|
116
|
+
# ViewTestCase#render carefully.
|
117
|
+
#
|
118
|
+
# ViewTestCase has a vastly expanded assertion library to help you out with
|
119
|
+
# testing. See ViewTestCase for all the helpful assertions you can use in
|
120
|
+
# your view tests.
|
121
|
+
#
|
122
|
+
# == Writing Controller Tests
|
123
|
+
#
|
124
|
+
# Controller tests are essentially functional tests without the view assertions.
|
125
|
+
#
|
126
|
+
# They live in test/controllers, subclass ControllerTestCase, and are
|
127
|
+
# named after the controller they are testing. For example,
|
128
|
+
# RouteControllerTest will live in the file
|
129
|
+
# test/controllers/route_controller_test.rb.
|
130
|
+
#
|
131
|
+
# === Example Controller Test Case
|
132
|
+
#
|
133
|
+
# require 'test/test_helper'
|
134
|
+
#
|
135
|
+
# # We are testing RouteController's actions
|
136
|
+
# class RouteControllerTest < Test::Rails::ControllerTestCase
|
137
|
+
#
|
138
|
+
# fixtures :users, :routes, :points, :photos
|
139
|
+
#
|
140
|
+
# # Testing the delete method
|
141
|
+
# def test_delete
|
142
|
+
# # A session accessor is provided instead of passing a hash to get.
|
143
|
+
# session[:username] = users(:herbert).username
|
144
|
+
#
|
145
|
+
# get :delete, :id => routes(:work).id
|
146
|
+
#
|
147
|
+
# # assert we got a 200
|
148
|
+
# assert_success
|
149
|
+
#
|
150
|
+
# # assert that instance variables are correctly assigned
|
151
|
+
# assert_assigned :action_title, "Deleting \"#{routes(:work).name}\""
|
152
|
+
# assert_assigned :route, routes(:work)
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# # ...
|
156
|
+
#
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# == Writing Abstract Test Cases
|
160
|
+
#
|
161
|
+
# Abstract test cases are a great way to refactor your tests and
|
162
|
+
# ensure you do not violate the DRY principal and share code between
|
163
|
+
# different test classes. If you have common setup code for your test
|
164
|
+
# classes you can create your own subclass of ControllerTestCase or
|
165
|
+
# ViewTestCase.
|
166
|
+
#
|
167
|
+
# === Example Abstract Test Case
|
168
|
+
#
|
169
|
+
# class RobotControllerTestCase < Test::Rails::ControllerTestCase
|
170
|
+
#
|
171
|
+
# fixtures :markets, :people
|
172
|
+
#
|
173
|
+
# def setup
|
174
|
+
# super
|
175
|
+
#
|
176
|
+
# # We're running tests in this class so we don't need to do any more
|
177
|
+
# # setup
|
178
|
+
# return if self.class == RobotControllerTestCase
|
179
|
+
#
|
180
|
+
# # Set our current host
|
181
|
+
# @host = 'www.test.robotcoop.com'
|
182
|
+
# util_set_host @host
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# ##
|
186
|
+
# # Sets the hostname to +host+ for this request.
|
187
|
+
#
|
188
|
+
# def util_set_host(hoston)
|
189
|
+
# @request.host = host
|
190
|
+
# end
|
191
|
+
#
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# = How to Audit Your Tests
|
195
|
+
#
|
196
|
+
# <tt>bin/rails_test_audit</tt> ensures that your view tests'
|
197
|
+
# +assign+s are compared against your controller tests'
|
198
|
+
# assert_assigned, warning you when you've forgotten to test
|
199
|
+
# something.
|
200
|
+
#
|
201
|
+
# Given:
|
202
|
+
#
|
203
|
+
# class RouteControllerTest < Test::Rails::ControllerTestCase
|
204
|
+
# def test_flickr_refresh
|
205
|
+
# get :flickr_refresh, :id => routes(:work).id
|
206
|
+
# assert_success
|
207
|
+
#
|
208
|
+
# assert_assigned :tz_name, 'Pacific Time (US & Canada)'
|
209
|
+
# end
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# And:
|
213
|
+
#
|
214
|
+
# class RouteViewTest < Test::Rails::ViewTestCase
|
215
|
+
# def test_flickr_refresh
|
216
|
+
# assigns[:route] = routes(:work)
|
217
|
+
# assigns[:tz_name] = 'Pacific Time (US & Canada)'
|
218
|
+
#
|
219
|
+
# render
|
220
|
+
#
|
221
|
+
# # ...
|
222
|
+
# end
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# +rails_test_audit+ will see that you don't have an +assert_assigned+
|
226
|
+
# for +route+ and will output:
|
227
|
+
#
|
228
|
+
# require 'test/test_helper'
|
229
|
+
#
|
230
|
+
# class RouteControllerTest < Test::Rails::ControllerTestCase
|
231
|
+
#
|
232
|
+
# def test_flickr_refresh
|
233
|
+
# assert_assigned :route, routes(:work)
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# = How 'rake test' Changed
|
239
|
+
#
|
240
|
+
# test:views and test:controllers targets get added so you can run just the
|
241
|
+
# view or controller tests.
|
242
|
+
#
|
243
|
+
# The "test" target runs tests in the following order: units, controllers,
|
244
|
+
# views, functionals, integration.
|
245
|
+
#
|
246
|
+
# The test target no longer runs all tests, it stops on the first
|
247
|
+
# failure. This way a failure in a unit test doesn't fill your screen
|
248
|
+
# with less important errors because the underlying failure also
|
249
|
+
# affected your controllers and views.
|
250
|
+
#
|
251
|
+
# The stats target is updated to account for controller and view tests.
|
252
|
+
|
253
|
+
module Test::Rails; end
|
254
|
+
|
255
|
+
class Object # :nodoc:
|
256
|
+
def self.path2class(klassname)
|
257
|
+
klassname.split('::').inject(Object) { |k,n| k.const_get n }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
require 'test/zentest_assertions'
|
262
|
+
require 'test/rails/test_case'
|
263
|
+
require 'test/rails/functional_test_case'
|
264
|
+
require 'test/rails/controller_test_case'
|
265
|
+
require 'test/rails/ivar_proxy'
|
266
|
+
require 'test/rails/view_test_case'
|
267
|
+
|
@@ -0,0 +1,357 @@
|
|
1
|
+
##
|
2
|
+
# ControllerTestCase allows controllers to be tested independent of their
|
3
|
+
# views.
|
4
|
+
#
|
5
|
+
# = Features
|
6
|
+
#
|
7
|
+
# * ActionMailer is already set up for you.
|
8
|
+
# * The session and flash accessors work on both sides of get/post/etc.
|
9
|
+
# * Optional automatic auditing for missing assert_assigns. See
|
10
|
+
# util_audit_assert_assigned
|
11
|
+
#
|
12
|
+
# = Naming
|
13
|
+
#
|
14
|
+
# The test class must be named after your controller class name, so if
|
15
|
+
# you're testing actions for the +RouteController+ you would name your
|
16
|
+
# test case +RouteControllerTest+.
|
17
|
+
#
|
18
|
+
# The test names should be in the form of +test_action_edgecase+ where
|
19
|
+
# 'action' corresponds to the name of the controller action, and
|
20
|
+
# 'edgecase' describes the scenario you are testing.
|
21
|
+
#
|
22
|
+
# If you are testing an action named 'show' your test should be named
|
23
|
+
# +test_show+. If your action behaves differently depending upon its
|
24
|
+
# arguments then you can make the test name descriptive like
|
25
|
+
# +test_show_photos+ and +test_show_no_photos+.
|
26
|
+
#
|
27
|
+
# = Examples
|
28
|
+
#
|
29
|
+
# == Typical Controller Test
|
30
|
+
#
|
31
|
+
# class RouteControllerTest < Test::Rails::ControllerTestCase
|
32
|
+
#
|
33
|
+
# fixtures :users, :routes, :points, :photos
|
34
|
+
#
|
35
|
+
# def test_delete
|
36
|
+
# # Set up our environment
|
37
|
+
# session[:username] = users(:herbert).username
|
38
|
+
#
|
39
|
+
# # perform the delet action
|
40
|
+
# get :delete, :id => routes(:work).id
|
41
|
+
#
|
42
|
+
# # Assert we got a 200
|
43
|
+
# assert_response :success
|
44
|
+
# # Ensure that @action_title is set properly
|
45
|
+
# assert_assigned :action_title, "Deleting \"#{routes(:work).name}\""
|
46
|
+
# # Ensure that @route is set properly
|
47
|
+
# assert_assigned :route, routes(:work)
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# == ActionMailer Test
|
53
|
+
#
|
54
|
+
# class ApplicationController < ActionController::Base
|
55
|
+
#
|
56
|
+
# ##
|
57
|
+
# # Send an email when we get an unhandled exception.
|
58
|
+
#
|
59
|
+
# def log_error(exception)
|
60
|
+
# case exception
|
61
|
+
# when ::ActionController::RoutingError,
|
62
|
+
# ::ActionController::UnknownAction,
|
63
|
+
# ::ActiveRecord::RecordNotFound then
|
64
|
+
# # ignore
|
65
|
+
# else
|
66
|
+
# unless RAILS_ENV == 'development' then
|
67
|
+
# Email.deliver_error exception, params, session, @request.env
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# ##
|
75
|
+
# # Dummy Controller just for testing.
|
76
|
+
#
|
77
|
+
# class DummyController < ApplicationController
|
78
|
+
#
|
79
|
+
# def error
|
80
|
+
# # Simulate a bug in our application
|
81
|
+
# raise RuntimeError
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# class DummyControllerTest < Test::Rails::ControllerTestCase
|
87
|
+
#
|
88
|
+
# def test_error_email
|
89
|
+
# # The rescue_action added by ControllerTestCase needs to be removed so
|
90
|
+
# # that exceptions fall through to the real error handler
|
91
|
+
# @controller.class.send :remove_method, :rescue_action
|
92
|
+
#
|
93
|
+
# # Fire off a request
|
94
|
+
# get :error
|
95
|
+
#
|
96
|
+
# # We should get a 500
|
97
|
+
# assert_response 500
|
98
|
+
#
|
99
|
+
# # And one delivered email
|
100
|
+
# assert_equal 1, @deliveries.length, 'error email sent'
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
#--
|
106
|
+
# TODO: Ensure that assert_tag doesn't work
|
107
|
+
# TODO: Cookie input.
|
108
|
+
|
109
|
+
class Test::Rails::ControllerTestCase < Test::Rails::FunctionalTestCase
|
110
|
+
|
111
|
+
NOTHING = Object.new # :nodoc:
|
112
|
+
|
113
|
+
DEFAULT_ASSIGNS = %w[
|
114
|
+
action_name before_filter_chain_aborted cookies flash headers
|
115
|
+
ignore_missing_templates loggedin_user logger params request
|
116
|
+
request_origin response session template template_class template_root url
|
117
|
+
user variables_added
|
118
|
+
]
|
119
|
+
|
120
|
+
def setup
|
121
|
+
return if self.class == Test::Rails::ControllerTestCase
|
122
|
+
|
123
|
+
@controller_class_name ||= self.class.name.sub 'Test', ''
|
124
|
+
|
125
|
+
super
|
126
|
+
|
127
|
+
@controller_class.send(:define_method, :rescue_action) { |e| raise e }
|
128
|
+
|
129
|
+
@deliveries = []
|
130
|
+
ActionMailer::Base.deliveries = @deliveries
|
131
|
+
|
132
|
+
# used by util_audit_assert_assigns
|
133
|
+
@assigns_asserted = []
|
134
|
+
@assigns_ignored ||= [] # untested assigns to ignore
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Excutes the request +action+ with +params+.
|
139
|
+
#
|
140
|
+
# See also: get, post, put, delete, head, xml_http_request
|
141
|
+
|
142
|
+
def process(action, parameters = nil)
|
143
|
+
parameters ||= {}
|
144
|
+
|
145
|
+
@request.recycle!
|
146
|
+
@request.env['REQUEST_METHOD'] ||= 'GET'
|
147
|
+
@request.action = action.to_s
|
148
|
+
|
149
|
+
@request.assign_parameters @controller_class.controller_path, action.to_s,
|
150
|
+
parameters
|
151
|
+
|
152
|
+
build_request_uri action, parameters
|
153
|
+
|
154
|
+
@controller.process @request, @response
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Performs a GET request on +action+ with +params+.
|
159
|
+
|
160
|
+
def get(action, parameters = nil)
|
161
|
+
@request.env['REQUEST_METHOD'] = 'GET'
|
162
|
+
process action, parameters
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Performs a HEAD request on +action+ with +params+.
|
167
|
+
|
168
|
+
def head(action, parameters = nil)
|
169
|
+
@request.env['REQUEST_METHOD'] = 'HEAD'
|
170
|
+
process action, parameters
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Performs a POST request on +action+ with +params+.
|
175
|
+
|
176
|
+
def post(action, parameters = nil)
|
177
|
+
@request.env['REQUEST_METHOD'] = 'POST'
|
178
|
+
process action, parameters
|
179
|
+
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Performs a PUT request on +action+ with +params+.
|
183
|
+
|
184
|
+
def put(action, parameters = nil)
|
185
|
+
@request.env['REQUEST_METHOD'] = 'PUT'
|
186
|
+
process action, parameters
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# Performs a DELETE request on +action+ with +params+.
|
191
|
+
|
192
|
+
def delete(action, parameters = nil)
|
193
|
+
@request.env['REQUEST_METHOD'] = 'DELETE'
|
194
|
+
process action, parameters
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Performs a XMLHttpRequest request using +request_method+ on +action+ with
|
199
|
+
# +params+.
|
200
|
+
|
201
|
+
def xml_http_request(request_method, action, parameters = nil)
|
202
|
+
@request.env['REQUEST_METHOD'] = request_method
|
203
|
+
|
204
|
+
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
205
|
+
@request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*'
|
206
|
+
|
207
|
+
result = process action, parameters
|
208
|
+
|
209
|
+
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
210
|
+
@request.env.delete 'HTTP_ACCEPT'
|
211
|
+
|
212
|
+
return result
|
213
|
+
end
|
214
|
+
|
215
|
+
##
|
216
|
+
# Friendly alias for xml_http_request
|
217
|
+
|
218
|
+
alias xhr xml_http_request
|
219
|
+
|
220
|
+
##
|
221
|
+
# Asserts that the assigns variable +ivar+ is assigned to +value+. If
|
222
|
+
# +value+ is omitted, asserts that assigns variable +ivar+ exists.
|
223
|
+
|
224
|
+
def assert_assigned(ivar, value = NOTHING)
|
225
|
+
ivar = ivar.to_s
|
226
|
+
@assigns_asserted << ivar
|
227
|
+
assert_includes assigns, ivar, "#{ivar.inspect} missing from assigns"
|
228
|
+
assert_equal value, assigns[ivar] unless value.equal? NOTHING
|
229
|
+
end
|
230
|
+
|
231
|
+
##
|
232
|
+
# Asserts the response content type matches +type+.
|
233
|
+
|
234
|
+
def assert_content_type(type, message = nil)
|
235
|
+
assert_equal type, @response.headers['Content-Type'], message
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Asserts that +key+ of flash has +content+. If +content+ is a Regexp, then
|
240
|
+
# the assertion will fail if the Regexp does not match.
|
241
|
+
#
|
242
|
+
# controller:
|
243
|
+
# flash[:notice] = 'Please log in'
|
244
|
+
#
|
245
|
+
# test:
|
246
|
+
# assert_flash :notice, 'Please log in'
|
247
|
+
|
248
|
+
def assert_flash(key, content)
|
249
|
+
assert flash.include?(key),
|
250
|
+
"#{key.inspect} missing from flash, has #{flash.keys.inspect}"
|
251
|
+
|
252
|
+
case content
|
253
|
+
when Regexp then
|
254
|
+
assert_match content, flash[key],
|
255
|
+
"Content of flash[#{key.inspect}] did not match"
|
256
|
+
else
|
257
|
+
assert_equal content, flash[key],
|
258
|
+
"Incorrect content in flash[#{key.inspect}]"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Asserts that the assigns variable +ivar+ is not set.
|
264
|
+
|
265
|
+
def deny_assigned(ivar)
|
266
|
+
deny_includes assigns, ivar
|
267
|
+
end
|
268
|
+
|
269
|
+
##
|
270
|
+
# Checks your assert_assigned tests against the instance variables in
|
271
|
+
# assigns. Fails if the two don't match.
|
272
|
+
#
|
273
|
+
# Add util_audit_assert_assigned to your teardown. If you have instance
|
274
|
+
# variables that you don't need to set (for example, were set in a
|
275
|
+
# before_filter in ApplicationController) then add them to the
|
276
|
+
# @assigns_ignored instance variable in your setup.
|
277
|
+
#
|
278
|
+
# = Example
|
279
|
+
#
|
280
|
+
# == Controller method
|
281
|
+
#
|
282
|
+
# class UserController < ApplicationController
|
283
|
+
# def new
|
284
|
+
# # ...
|
285
|
+
#
|
286
|
+
# @login_form = false
|
287
|
+
# end
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# == Test setup:
|
291
|
+
#
|
292
|
+
# class UserControllerTest < Test::Rails::ControllerTestCase
|
293
|
+
#
|
294
|
+
# def teardown
|
295
|
+
# super
|
296
|
+
# util_audit_assert_assigned
|
297
|
+
# end
|
298
|
+
#
|
299
|
+
# def test_new
|
300
|
+
# get :new
|
301
|
+
#
|
302
|
+
# assert_response :success
|
303
|
+
# # no assert_assigns for @login_form
|
304
|
+
# end
|
305
|
+
#
|
306
|
+
# end
|
307
|
+
#
|
308
|
+
# == Output
|
309
|
+
# 1) Failure:
|
310
|
+
# test_new(UserControllerTest)
|
311
|
+
# [[...]/controller_test_case.rb:331:in `util_audit_assert_assigned'
|
312
|
+
# [...]/user_controller_test.rb:14:in `teardown_without_fixtures'
|
313
|
+
# [...]fixtures.rb:555:in `teardown']:
|
314
|
+
# You are missing these assert_assigned assertions:
|
315
|
+
# assert_assigned :login_form #, some_value
|
316
|
+
# .
|
317
|
+
|
318
|
+
def util_audit_assert_assigned
|
319
|
+
return unless @controller.send :performed?
|
320
|
+
all_assigns = assigns.keys.sort
|
321
|
+
|
322
|
+
assigns_ignored = DEFAULT_ASSIGNS | @assigns_ignored
|
323
|
+
|
324
|
+
assigns_created = all_assigns - assigns_ignored
|
325
|
+
assigns_asserted = @assigns_asserted - assigns_ignored
|
326
|
+
|
327
|
+
assigns_created = assigns_created
|
328
|
+
assigns_asserted = assigns_asserted
|
329
|
+
|
330
|
+
assigns_missing = assigns_created - assigns_asserted
|
331
|
+
|
332
|
+
return if assigns_missing.empty?
|
333
|
+
|
334
|
+
message = []
|
335
|
+
message << "You are missing these assert_assigned assertions:"
|
336
|
+
assigns_missing.sort.each do |ivar|
|
337
|
+
message << " assert_assigned #{ivar.intern.inspect} #, some_value"
|
338
|
+
end
|
339
|
+
message << nil # stupid '.'
|
340
|
+
|
341
|
+
flunk message.join("\n")
|
342
|
+
end
|
343
|
+
|
344
|
+
private
|
345
|
+
|
346
|
+
def build_request_uri(action, parameters)
|
347
|
+
return if @request.env['REQUEST_URI']
|
348
|
+
|
349
|
+
options = @controller.send :rewrite_options, parameters
|
350
|
+
options.update :only_path => true, :action => action
|
351
|
+
|
352
|
+
url = ActionController::UrlRewriter.new @request, parameters
|
353
|
+
@request.set_REQUEST_URI url.rewrite(options)
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
|