Spec-Zone.ru › Ruby on Rails 8.1

класс ActionDispatch::IntegrationTest

Родительский класс:
ActiveSupport::TestCase
Подключённые модули:
ActionDispatch::TestProcess::FixtureFile, ActionDispatch::IntegrationTest::Behavior

Интеграционный тест охватывает несколько контроллеров и действий, объединяя их, чтобы убедиться, что они работают вместе должным образом. Он проверяет приложение полнее, чем модульные или функциональные тесты, задействуя весь стек — от диспетчера до базы данных.

В простейшем случае достаточно унаследовать класс от 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 передаёт заголовок Accept со значением «application/json» (тем самым задавая формат запроса JSON, если он не переопределён), устанавливает тип содержимого «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 по тестированию.

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API