集成测试跨越多个控制器和操作,将它们联系起来,以确保它们按预期协同工作。它比单元测试或功能测试更全面地进行测试,从而测试从调度器到数据库的整个堆栈。
最简单的做法是,您只需继承 IntegrationTest 并使用 Integration::RequestHelpers#get 和/或 Integration::RequestHelpers#post 方法编写测试。
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
但是,您也可以在每个测试中拥有多个会话实例,甚至可以通过断言和方法扩展这些实例,以创建特定于应用程序的非常强大的测试 DSL。您甚至可以引用您定义的任何命名路由。
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
另一个更长的例子是
一个简单的集成测试,它测试多个控制器
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_dom 'h1', 'Articles' end end
如您所见,集成测试涉及多个控制器,并从数据库到调度器测试整个堆栈。此外,您可以在一个测试中同时打开多个会话实例,并通过断言方法扩展这些实例,为您的应用程序创建非常强大的测试 DSL(领域特定语言)。
这是一个多会话和自定义 DSL 在集成测试中的示例
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_dom '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
有关如何使用 get 等的帮助,请参阅 请求助手文档。
更改请求编码¶ ↑
您还可以通过设置请求的编码方式来轻松测试您的 JSON API。
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" => Article.last.id, "title" => "Ahoy!" }, response.parsed_body) end end
as 选项会传递一个“application/json”的 Accept 头(从而将请求格式设置为 JSON,除非被覆盖),将 content type 设置为“application/json”,并将参数编码为 JSON。
对响应调用 TestResponse#parsed_body 会根据最后一个响应 MIME 类型解析响应体。
开箱即用,只支持 :json。但是,对于您注册的任何自定义 MIME 类型,您可以通过以下方式添加自己的编码器:
ActionDispatch::IntegrationTest.register_encoder :wibble, param_encoder: -> params { params.to_wibble }, response_parser: -> body { body }
其中 param_encoder 定义了参数的编码方式,response_parser 定义了响应体如何通过 TestResponse#parsed_body 进行解析。
有关更多信息,请参阅 Rails 测试指南。