Skip to content
This repository
Browse code

extract ActionController::TestCase::Behavior

- this makes it possible for other test frameworks
  to hook into testing facilities provided by Rails
  without having to subclass AC::TestCase.

[#4474 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
  • Loading branch information...
commit 176fbfd66fe500ddfd04ffeb08ed014e705a82f9 1 parent 9b5a1f7
David Chelimsky authored April 25, 2010 josevalim committed April 26, 2010

Showing 1 changed file with 133 additions and 126 deletions. Show diff stats Hide diff stats

  1. 259  actionpack/lib/action_controller/test_case.rb
259  actionpack/lib/action_controller/test_case.rb
@@ -283,165 +283,143 @@ def initialize(session = {})
283 283
   #
284 284
   #  assert_redirected_to page_url(:title => 'foo')
285 285
   class TestCase < ActiveSupport::TestCase
286  
-    include ActionDispatch::TestProcess
287  
-    include ActionController::TemplateAssertions
  286
+    module Behavior
  287
+      extend ActiveSupport::Concern
  288
+      include ActionDispatch::TestProcess
288 289
 
289  
-    attr_reader :response, :request
  290
+      attr_reader :response, :request
290 291
 
291  
-    # Executes a request simulating GET HTTP method and set/volley the response
292  
-    def get(action, parameters = nil, session = nil, flash = nil)
293  
-      process(action, parameters, session, flash, "GET")
294  
-    end
  292
+      module ClassMethods
295 293
 
296  
-    # Executes a request simulating POST HTTP method and set/volley the response
297  
-    def post(action, parameters = nil, session = nil, flash = nil)
298  
-      process(action, parameters, session, flash, "POST")
299  
-    end
  294
+        # Sets the controller class name. Useful if the name can't be inferred from test class.
  295
+        # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
  296
+        def tests(controller_class)
  297
+          self.controller_class = controller_class
  298
+        end
  299
+        
  300
+        def controller_class=(new_class)
  301
+          prepare_controller_class(new_class) if new_class
  302
+          write_inheritable_attribute(:controller_class, new_class)
  303
+        end
300 304
 
301  
-    # Executes a request simulating PUT HTTP method and set/volley the response
302  
-    def put(action, parameters = nil, session = nil, flash = nil)
303  
-      process(action, parameters, session, flash, "PUT")
304  
-    end
  305
+        def controller_class
  306
+          if current_controller_class = read_inheritable_attribute(:controller_class)
  307
+            current_controller_class
  308
+          else
  309
+            self.controller_class = determine_default_controller_class(name)
  310
+          end
  311
+        end
305 312
 
306  
-    # Executes a request simulating DELETE HTTP method and set/volley the response
307  
-    def delete(action, parameters = nil, session = nil, flash = nil)
308  
-      process(action, parameters, session, flash, "DELETE")
309  
-    end
  313
+        def determine_default_controller_class(name)
  314
+          name.sub(/Test$/, '').constantize
  315
+        rescue NameError
  316
+          nil
  317
+        end
310 318
 
311  
-    # Executes a request simulating HEAD HTTP method and set/volley the response
312  
-    def head(action, parameters = nil, session = nil, flash = nil)
313  
-      process(action, parameters, session, flash, "HEAD")
314  
-    end
  319
+        def prepare_controller_class(new_class)
  320
+          new_class.send :include, ActionController::TestCase::RaiseActionExceptions
  321
+        end
315 322
 
316  
-    def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
317  
-      @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
318  
-      @request.env['HTTP_ACCEPT'] ||=  [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
319  
-      returning __send__(request_method, action, parameters, session, flash) do
320  
-        @request.env.delete 'HTTP_X_REQUESTED_WITH'
321  
-        @request.env.delete 'HTTP_ACCEPT'
322 323
       end
323  
-    end
324  
-    alias xhr :xml_http_request
325  
-
326  
-    def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
327  
-      # Sanity check for required instance variables so we can give an
328  
-      # understandable error message.
329  
-      %w(@routes @controller @request @response).each do |iv_name|
330  
-        if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
331  
-          raise "#{iv_name} is nil: make sure you set it in your test's setup method."
332  
-        end
  324
+
  325
+      # Executes a request simulating GET HTTP method and set/volley the response
  326
+      def get(action, parameters = nil, session = nil, flash = nil)
  327
+        process(action, parameters, session, flash, "GET")
333 328
       end
334 329
 
335  
-      @request.recycle!
336  
-      @response.recycle!
337  
-      @controller.response_body = nil
338  
-      @controller.formats = nil
339  
-      @controller.params = nil
340  
-
341  
-      @html_document = nil
342  
-      @request.env['REQUEST_METHOD'] = http_method
343  
-
344  
-      parameters ||= {}
345  
-      @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
346  
-
347  
-      @request.session = ActionController::TestSession.new(session) unless session.nil?
348  
-      @request.session["flash"] = @request.flash.update(flash || {})
349  
-      @request.session["flash"].sweep
350  
-
351  
-      @controller.request = @request
352  
-      @controller.params.merge!(parameters)
353  
-      build_request_uri(action, parameters)
354  
-      Base.class_eval { include Testing }
355  
-      @controller.process_with_new_base_test(@request, @response)
356  
-      @request.session.delete('flash') if @request.session['flash'].blank?
357  
-      @response
358  
-    end
  330
+      # Executes a request simulating POST HTTP method and set/volley the response
  331
+      def post(action, parameters = nil, session = nil, flash = nil)
  332
+        process(action, parameters, session, flash, "POST")
  333
+      end
359 334
 
360  
-    include ActionDispatch::Assertions
  335
+      # Executes a request simulating PUT HTTP method and set/volley the response
  336
+      def put(action, parameters = nil, session = nil, flash = nil)
  337
+        process(action, parameters, session, flash, "PUT")
  338
+      end
361 339
 
362  
-    # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
363  
-    # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
364  
-    # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
365  
-    # than 0.0.0.0.
366  
-    #
367  
-    # The exception is stored in the exception accessor for further inspection.
368  
-    module RaiseActionExceptions
369  
-      def self.included(base)
370  
-        base.class_eval do
371  
-          attr_accessor :exception
372  
-          protected :exception, :exception=
373  
-        end
  340
+      # Executes a request simulating DELETE HTTP method and set/volley the response
  341
+      def delete(action, parameters = nil, session = nil, flash = nil)
  342
+        process(action, parameters, session, flash, "DELETE")
374 343
       end
375 344
 
376  
-      protected
377  
-        def rescue_action_without_handler(e)
378  
-          self.exception = e
  345
+      # Executes a request simulating HEAD HTTP method and set/volley the response
  346
+      def head(action, parameters = nil, session = nil, flash = nil)
  347
+        process(action, parameters, session, flash, "HEAD")
  348
+      end
379 349
 
380  
-          if request.remote_addr == "0.0.0.0"
381  
-            raise(e)
382  
-          else
383  
-            super(e)
  350
+      def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
  351
+        @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
  352
+        @request.env['HTTP_ACCEPT'] ||=  [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
  353
+        returning __send__(request_method, action, parameters, session, flash) do
  354
+          @request.env.delete 'HTTP_X_REQUESTED_WITH'
  355
+          @request.env.delete 'HTTP_ACCEPT'
  356
+        end
  357
+      end
  358
+      alias xhr :xml_http_request
  359
+
  360
+      def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
  361
+        # Sanity check for required instance variables so we can give an
  362
+        # understandable error message.
  363
+        %w(@routes @controller @request @response).each do |iv_name|
  364
+          if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
  365
+            raise "#{iv_name} is nil: make sure you set it in your test's setup method."
384 366
           end
385 367
         end
386  
-    end
387 368
 
388  
-    setup :setup_controller_request_and_response
  369
+        @request.recycle!
  370
+        @response.recycle!
  371
+        @controller.response_body = nil
  372
+        @controller.formats = nil
  373
+        @controller.params = nil
389 374
 
390  
-    @@controller_class = nil
  375
+        @html_document = nil
  376
+        @request.env['REQUEST_METHOD'] = http_method
391 377
 
392  
-    class << self
393  
-      # Sets the controller class name. Useful if the name can't be inferred from test class.
394  
-      # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
395  
-      def tests(controller_class)
396  
-        self.controller_class = controller_class
397  
-      end
  378
+        parameters ||= {}
  379
+        @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
398 380
 
399  
-      def controller_class=(new_class)
400  
-        prepare_controller_class(new_class) if new_class
401  
-        write_inheritable_attribute(:controller_class, new_class)
402  
-      end
  381
+        @request.session = ActionController::TestSession.new(session) unless session.nil?
  382
+        @request.session["flash"] = @request.flash.update(flash || {})
  383
+        @request.session["flash"].sweep
403 384
 
404  
-      def controller_class
405  
-        if current_controller_class = read_inheritable_attribute(:controller_class)
406  
-          current_controller_class
407  
-        else
408  
-          self.controller_class = determine_default_controller_class(name)
409  
-        end
  385
+        @controller.request = @request
  386
+        @controller.params.merge!(parameters)
  387
+        build_request_uri(action, parameters)
  388
+        Base.class_eval { include Testing }
  389
+        @controller.process_with_new_base_test(@request, @response)
  390
+        @request.session.delete('flash') if @request.session['flash'].blank?
  391
+        @response
410 392
       end
411 393
 
412  
-      def determine_default_controller_class(name)
413  
-        name.sub(/Test$/, '').constantize
414  
-      rescue NameError
415  
-        nil
416  
-      end
  394
+      def setup_controller_request_and_response
  395
+        @request = TestRequest.new
  396
+        @response = TestResponse.new
417 397
 
418  
-      def prepare_controller_class(new_class)
419  
-        new_class.send :include, RaiseActionExceptions
420  
-      end
421  
-    end
  398
+        if klass = self.class.controller_class
  399
+          @controller ||= klass.new rescue nil
  400
+        end
422 401
 
423  
-    def setup_controller_request_and_response
424  
-      @request = TestRequest.new
425  
-      @response = TestResponse.new
  402
+        @request.env.delete('PATH_INFO')
426 403
 
427  
-      if klass = self.class.controller_class
428  
-        @controller ||= klass.new rescue nil
  404
+        if @controller
  405
+          @controller.request = @request
  406
+          @controller.params = {}
  407
+        end
429 408
       end
430 409
 
431  
-      @request.env.delete('PATH_INFO')
432  
-
433  
-      if @controller
434  
-        @controller.request = @request
435  
-        @controller.params = {}
  410
+      # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
  411
+      def rescue_action_in_public!
  412
+        @request.remote_addr = '208.77.188.166' # example.com
436 413
       end
437  
-    end
438 414
 
439  
-    # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
440  
-    def rescue_action_in_public!
441  
-      @request.remote_addr = '208.77.188.166' # example.com
442  
-    end
  415
+      included do
  416
+        include ActionController::TemplateAssertions
  417
+        include ActionDispatch::Assertions
  418
+        setup :setup_controller_request_and_response
  419
+      end
443 420
 
444 421
     private
  422
+
445 423
       def build_request_uri(action, parameters)
446 424
         unless @request.env["PATH_INFO"]
447 425
           options = @controller.__send__(:url_options).merge(parameters)
@@ -459,4 +437,33 @@ def build_request_uri(action, parameters)
459 437
         end
460 438
       end
461 439
     end
  440
+
  441
+    # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
  442
+    # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
  443
+    # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
  444
+    # than 0.0.0.0.
  445
+    #
  446
+    # The exception is stored in the exception accessor for further inspection.
  447
+    module RaiseActionExceptions
  448
+      def self.included(base)
  449
+        base.class_eval do
  450
+          attr_accessor :exception
  451
+          protected :exception, :exception=
  452
+        end
  453
+      end
  454
+
  455
+      protected
  456
+        def rescue_action_without_handler(e)
  457
+          self.exception = e
  458
+
  459
+          if request.remote_addr == "0.0.0.0"
  460
+            raise(e)
  461
+          else
  462
+            super(e)
  463
+          end
  464
+        end
  465
+    end
  466
+
  467
+    include Behavior
  468
+  end
462 469
 end

1 note on commit 176fbfd

Aslak Hellesøy

Fantastic! This is great news for alternative test frameworks.

Please sign in to comment.
Something went wrong with that request. Please try again.