ZenTest 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|