An integration test spans multiple controllers and actions, tying them all together to ensure they work together as expected. It tests more completely than either unit or functional tests do, exercising the entire stack, from the dispatcher to the database.

At its simplest, you simply extend IntegrationTest and write your tests using the get/post methods:

require "test_helper"

class ExampleTest < ActionDispatch::IntegrationTest
  fixtures :people

  def test_login
    # get the login page
    get "/login"
    assert_equal 200, status

    # post the login and follow through to the home page
    post "/login", :username => people(:jamis).username,
      :password => people(:jamis).password
    follow_redirect!
    assert_equal 200, status
    assert_equal "/home", path
  end
end

However, you can also have multiple session instances open per test, and even extend those instances with assertions and methods to create a very powerful testing DSL that is specific for your application. You can even reference any named routes you happen to have defined.

require "test_helper"

class AdvancedTest < ActionDispatch::IntegrationTest
  fixtures :people, :rooms

  def test_login_and_speak
    jamis, david = login(:jamis), login(:david)
    room = rooms(:office)

    jamis.enter(room)
    jamis.speak(room, "anybody home?")

    david.enter(room)
    david.speak(room, "hello!")
  end

  private

    module CustomAssertions
      def enter(room)
        # reference a named route, for maximum internal consistency!
        get(room_url(:id => room.id))
        assert(...)
        ...
      end

      def speak(room, message)
        xml_http_request "/say/#{room.id}", :message => message
        assert(...)
        ...
      end
    end

    def login(who)
      open_session do |sess|
        sess.extend(CustomAssertions)
        who = people(who)
        sess.post "/login", :username => who.username,
          :password => who.password
        assert(...)
      end
    end
end
Namespace
Methods
A
B
S
U
W
Included Modules
Class Public methods
app()
# File actionpack/lib/action_dispatch/testing/integration.rb, line 479
def self.app
  # DEPRECATE Rails application fallback
  # This should be set by the initializer
  @@app || (defined?(Rails.application) && Rails.application) || nil
end
app=(app)
# File actionpack/lib/action_dispatch/testing/integration.rb, line 485
def self.app=(app)
  @@app = app
end
build_app(routes = nil)
# File actionpack/test/abstract_unit.rb, line 175
def self.build_app(routes = nil)
  RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
    middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
    middleware.use "ActionDispatch::DebugExceptions"
    middleware.use "ActionDispatch::Callbacks"
    middleware.use "ActionDispatch::ParamsParser"
    middleware.use "ActionDispatch::Cookies"
    middleware.use "ActionDispatch::Flash"
    middleware.use "ActionDispatch::Head"
    yield(middleware) if block_given?
  end
end
stub_controllers()
# File actionpack/test/abstract_unit.rb, line 203
def self.stub_controllers
  old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
  ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
  ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
  yield ActionDispatch::Routing::RouteSet.new
ensure
  ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
  ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
end
Instance Public methods
app()
# File actionpack/lib/action_dispatch/testing/integration.rb, line 489
def app
  super || self.class.app
end
url_options()
# File actionpack/lib/action_dispatch/testing/integration.rb, line 493
def url_options
  reset! unless integration_session
  integration_session.url_options
end
with_autoload_path(path)
# File actionpack/test/abstract_unit.rb, line 225
def with_autoload_path(path)
  path = File.join(File.dirname(__FILE__), "fixtures", path)
  if ActiveSupport::Dependencies.autoload_paths.include?(path)
    yield
  else
    begin
      ActiveSupport::Dependencies.autoload_paths << path
      yield
    ensure
      ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
      ActiveSupport::Dependencies.clear
    end
  end
end
with_routing(&block)
# File actionpack/test/abstract_unit.rb, line 213
def with_routing(&block)
  temporary_routes = ActionDispatch::Routing::RouteSet.new
  old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
  old_routes = SharedTestRoutes
  silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }

  yield temporary_routes
ensure
  self.class.app = old_app
  silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end