2007-12-21 08:48:59 +01:00
|
|
|
require 'active_support/test_case'
|
2009-02-04 21:26:08 +01:00
|
|
|
require 'action_controller/test_process'
|
2007-12-21 08:48:59 +01:00
|
|
|
|
|
|
|
module ActionController
|
2008-10-27 07:47:01 +01:00
|
|
|
# Superclass for ActionController functional tests. Functional tests allow you to
|
|
|
|
# test a single controller action per test method. This should not be confused with
|
|
|
|
# integration tests (see ActionController::IntegrationTest), which are more like
|
|
|
|
# "stories" that can involve multiple controllers and mutliple actions (i.e. multiple
|
|
|
|
# different HTTP requests).
|
|
|
|
#
|
|
|
|
# == Basic example
|
|
|
|
#
|
|
|
|
# Functional tests are written as follows:
|
|
|
|
# 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate
|
|
|
|
# an HTTP request.
|
|
|
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
|
|
|
# the controller's HTTP response, the database contents, etc.
|
|
|
|
#
|
|
|
|
# For example:
|
|
|
|
#
|
|
|
|
# class BooksControllerTest < ActionController::TestCase
|
|
|
|
# def test_create
|
|
|
|
# # Simulate a POST response with the given HTTP parameters.
|
|
|
|
# post(:create, :book => { :title => "Love Hina" })
|
|
|
|
#
|
|
|
|
# # Assert that the controller tried to redirect us to
|
|
|
|
# # the created book's URI.
|
|
|
|
# assert_response :found
|
|
|
|
#
|
|
|
|
# # Assert that the controller really put the book in the database.
|
|
|
|
# assert_not_nil Book.find_by_title("Love Hina")
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# == Special instance variables
|
|
|
|
#
|
|
|
|
# ActionController::TestCase will also automatically provide the following instance
|
|
|
|
# variables for use in the tests:
|
|
|
|
#
|
|
|
|
# <b>@controller</b>::
|
|
|
|
# The controller instance that will be tested.
|
|
|
|
# <b>@request</b>::
|
|
|
|
# An ActionController::TestRequest, representing the current HTTP
|
|
|
|
# request. You can modify this object before sending the HTTP request. For example,
|
|
|
|
# you might want to set some session properties before sending a GET request.
|
|
|
|
# <b>@response</b>::
|
|
|
|
# An ActionController::TestResponse object, representing the response
|
|
|
|
# of the last HTTP response. In the above example, <tt>@response</tt> becomes valid
|
|
|
|
# after calling +post+. If the various assert methods are not sufficient, then you
|
|
|
|
# may use this object to inspect the HTTP response in detail.
|
|
|
|
#
|
|
|
|
# (Earlier versions of Rails required each functional test to subclass
|
|
|
|
# Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
|
|
|
|
#
|
|
|
|
# == Controller is automatically inferred
|
|
|
|
#
|
|
|
|
# ActionController::TestCase will automatically infer the controller under test
|
|
|
|
# from the test class name. If the controller cannot be inferred from the test
|
|
|
|
# class name, you can explicity set it with +tests+.
|
|
|
|
#
|
|
|
|
# class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase
|
|
|
|
# tests WidgetController
|
|
|
|
# end
|
2009-02-04 21:26:08 +01:00
|
|
|
#
|
|
|
|
# == Testing controller internals
|
|
|
|
#
|
|
|
|
# In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
|
|
|
|
# can be used against. These collections are:
|
|
|
|
#
|
|
|
|
# * assigns: Instance variables assigned in the action that are available for the view.
|
|
|
|
# * session: Objects being saved in the session.
|
|
|
|
# * flash: The flash objects currently in the session.
|
|
|
|
# * cookies: Cookies being sent to the user on this request.
|
|
|
|
#
|
|
|
|
# These collections can be used just like any other hash:
|
|
|
|
#
|
|
|
|
# assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
|
|
|
|
# assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
|
|
|
|
# assert flash.empty? # makes sure that there's nothing in the flash
|
|
|
|
#
|
|
|
|
# For historic reasons, the assigns hash uses string-based keys. So assigns[:person] won't work, but assigns["person"] will. To
|
|
|
|
# appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
|
|
|
|
# So assigns(:person) will work just like assigns["person"], but again, assigns[:person] will not work.
|
|
|
|
#
|
|
|
|
# On top of the collections, you have the complete url that a given action redirected to available in redirect_to_url.
|
|
|
|
#
|
|
|
|
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
|
|
|
|
# action call which can then be asserted against.
|
|
|
|
#
|
|
|
|
# == Manipulating the request collections
|
|
|
|
#
|
|
|
|
# The collections described above link to the response, so you can test if what the actions were expected to do happened. But
|
|
|
|
# sometimes you also want to manipulate these collections in the incoming request. This is really only relevant for sessions
|
|
|
|
# and cookies, though. For sessions, you just do:
|
|
|
|
#
|
|
|
|
# @request.session[:key] = "value"
|
|
|
|
# @request.cookies["key"] = "value"
|
|
|
|
#
|
|
|
|
# == Testing named routes
|
|
|
|
#
|
|
|
|
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# assert_redirected_to page_url(:title => 'foo')
|
2007-12-21 08:48:59 +01:00
|
|
|
class TestCase < ActiveSupport::TestCase
|
2009-02-04 21:26:08 +01:00
|
|
|
include TestProcess
|
|
|
|
|
|
|
|
module Assertions
|
|
|
|
%w(response selector tag dom routing model).each do |kind|
|
|
|
|
include ActionController::Assertions.const_get("#{kind.camelize}Assertions")
|
|
|
|
end
|
|
|
|
|
|
|
|
def clean_backtrace(&block)
|
|
|
|
yield
|
|
|
|
rescue ActiveSupport::TestCase::Assertion => error
|
|
|
|
framework_path = Regexp.new(File.expand_path("#{File.dirname(__FILE__)}/assertions"))
|
|
|
|
error.backtrace.reject! { |line| File.expand_path(line) =~ framework_path }
|
|
|
|
raise
|
|
|
|
end
|
|
|
|
end
|
|
|
|
include Assertions
|
|
|
|
|
2008-05-18 06:22:34 +02:00
|
|
|
# When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
|
|
|
|
# (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
|
|
|
|
# rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
|
|
|
|
# than 0.0.0.0.
|
|
|
|
#
|
|
|
|
# The exception is stored in the exception accessor for further inspection.
|
|
|
|
module RaiseActionExceptions
|
2009-02-28 02:23:00 +01:00
|
|
|
def self.included(base)
|
|
|
|
base.class_eval do
|
|
|
|
attr_accessor :exception
|
|
|
|
protected :exception, :exception=
|
|
|
|
end
|
|
|
|
end
|
2008-05-18 06:22:34 +02:00
|
|
|
|
2009-02-28 02:23:00 +01:00
|
|
|
protected
|
2009-02-04 21:26:08 +01:00
|
|
|
def rescue_action_without_handler(e)
|
|
|
|
self.exception = e
|
|
|
|
|
|
|
|
if request.remote_addr == "0.0.0.0"
|
|
|
|
raise(e)
|
|
|
|
else
|
|
|
|
super(e)
|
|
|
|
end
|
2008-05-18 06:22:34 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
setup :setup_controller_request_and_response
|
|
|
|
|
2007-12-21 08:48:59 +01:00
|
|
|
@@controller_class = nil
|
2008-05-18 06:22:34 +02:00
|
|
|
|
2007-12-21 08:48:59 +01:00
|
|
|
class << self
|
2008-10-27 07:47:01 +01:00
|
|
|
# Sets the controller class name. Useful if the name can't be inferred from test class.
|
|
|
|
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
|
2007-12-21 08:48:59 +01:00
|
|
|
def tests(controller_class)
|
|
|
|
self.controller_class = controller_class
|
|
|
|
end
|
|
|
|
|
|
|
|
def controller_class=(new_class)
|
2009-02-04 21:26:08 +01:00
|
|
|
prepare_controller_class(new_class) if new_class
|
2007-12-21 08:48:59 +01:00
|
|
|
write_inheritable_attribute(:controller_class, new_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
def controller_class
|
|
|
|
if current_controller_class = read_inheritable_attribute(:controller_class)
|
|
|
|
current_controller_class
|
|
|
|
else
|
2008-05-18 06:22:34 +02:00
|
|
|
self.controller_class = determine_default_controller_class(name)
|
2007-12-21 08:48:59 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def determine_default_controller_class(name)
|
|
|
|
name.sub(/Test$/, '').constantize
|
|
|
|
rescue NameError
|
2009-02-04 21:26:08 +01:00
|
|
|
nil
|
2007-12-21 08:48:59 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def prepare_controller_class(new_class)
|
2008-05-18 06:22:34 +02:00
|
|
|
new_class.send :include, RaiseActionExceptions
|
2007-12-21 08:48:59 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-05-18 06:22:34 +02:00
|
|
|
def setup_controller_request_and_response
|
2009-02-04 21:26:08 +01:00
|
|
|
@request = TestRequest.new
|
2008-05-18 06:22:34 +02:00
|
|
|
@response = TestResponse.new
|
2008-10-27 07:47:01 +01:00
|
|
|
|
2009-02-04 21:26:08 +01:00
|
|
|
if klass = self.class.controller_class
|
|
|
|
@controller ||= klass.new rescue nil
|
|
|
|
end
|
|
|
|
|
|
|
|
if @controller
|
|
|
|
@controller.request = @request
|
|
|
|
@controller.params = {}
|
|
|
|
@controller.send(:initialize_current_url)
|
|
|
|
end
|
2007-12-21 08:48:59 +01:00
|
|
|
end
|
2008-05-18 06:22:34 +02:00
|
|
|
|
|
|
|
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
|
|
|
|
def rescue_action_in_public!
|
|
|
|
@request.remote_addr = '208.77.188.166' # example.com
|
|
|
|
end
|
2009-02-04 21:26:08 +01:00
|
|
|
end
|
2008-10-27 07:47:01 +01:00
|
|
|
end
|