Class: ActionDispatch::IntegrationTest
- Inherits:
-
ActiveSupport::TestCase
- Object
- ActiveSupport::TestCase
- ActionDispatch::IntegrationTest
- Includes:
- Behavior
- Defined in:
- lib/action_dispatch/testing/integration.rb
Overview
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", params: { 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)
post "/say/#{room.id}", xhr: true, params: { message: message }
assert(...)
...
end
end
def login(who)
open_session do |sess|
sess.extend(CustomAssertions)
who = people(who)
sess.post "/login", params: { username: who.username,
password: who.password }
assert(...)
end
end
end
Another longer example would be:
A simple integration test that exercises multiple controllers:
require 'test_helper'
class UserFlowsTest < ActionDispatch::IntegrationTest
test "login and browse site" do
# login via https
https!
get "/login"
assert_response :success
post "/login", params: { username: users(:david).username, password: users(:david).password }
follow_redirect!
assert_equal '/welcome', path
assert_equal 'Welcome david!', flash[:notice]
https!(false)
get "/articles/all"
assert_response :success
assert_select 'h1', 'Articles'
end
end
As you can see the integration test involves multiple controllers and exercises the entire stack from database to dispatcher. In addition you can have multiple session instances open simultaneously in a test and extend those instances with assertion methods to create a very powerful testing DSL (domain-specific language) just for your application.
Here’s an example of multiple sessions and custom DSL in an integration test
require 'test_helper'
class UserFlowsTest < ActionDispatch::IntegrationTest
test "login and browse site" do
# User david logs in
david = login(:david)
# User guest logs in
guest = login(:guest)
# Both are now available in different sessions
assert_equal 'Welcome david!', david.flash[:notice]
assert_equal 'Welcome guest!', guest.flash[:notice]
# User david can browse site
david.browses_site
# User guest can browse site as well
guest.browses_site
# Continue with other assertions
end
private
module CustomDsl
def browses_site
get "/products/all"
assert_response :success
assert_select 'h1', 'Products'
end
end
def login(user)
open_session do |sess|
sess.extend(CustomDsl)
u = users(user)
sess.https!
sess.post "/login", params: { username: u.username, password: u.password }
assert_equal '/welcome', sess.path
sess.https!(false)
end
end
end
You can also test your JSON API easily by setting what the request should be encoded as:
require 'test_helper'
class ApiTest < ActionDispatch::IntegrationTest
test 'creates articles' do
assert_difference -> { Article.count } do
post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json
end
assert_response :success
assert_equal({ id: Arcticle.last.id, title: 'Ahoy!' }, response.parsed_body)
end
end
The ‘as` option sets the format to JSON, sets the content type to ’application/json’ and encodes the parameters as JSON.
Calling ‘parsed_body` on the response parses the response body as what the last request was encoded as. If the request wasn’t encoded ‘as` something, it’s the same as calling ‘body`.
For any custom MIME Types you’ve registered, you can even add your own encoders with:
ActionDispatch::IntegrationTest.register_encoder :wibble,
param_encoder: -> params { params.to_wibble },
response_parser: -> body { body }
Where ‘param_encoder` defines how the params should be encoded and `response_parser` defines how the response body should be parsed through `parsed_body`.
Consult the Rails Testing Guide for more.
Defined Under Namespace
Modules: Behavior, UrlOptions
Constant Summary
Constants included from ActionDispatch::Integration::Runner
ActionDispatch::Integration::Runner::APP_SESSIONS
Constants included from Assertions::ResponseAssertions
Assertions::ResponseAssertions::RESPONSE_PREDICATES
Instance Attribute Summary
Attributes included from ActionDispatch::Integration::Runner
Method Summary
Methods included from Behavior
Methods included from ActionController::TemplateAssertions
Methods included from ActionDispatch::Integration::Runner
#before_setup, #copy_session_variables!, #create_session, #default_url_options, #default_url_options=, #integration_session, #method_missing, #open_session, #remove!, #reset!, #respond_to?
Methods included from Assertions
Methods included from Assertions::RoutingAssertions
#assert_generates, #assert_recognizes, #assert_routing, #method_missing, #with_routing
Methods included from Assertions::ResponseAssertions
#assert_redirected_to, #assert_response
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class ActionDispatch::Integration::Runner