Интеграционное тестирование в Spring: цели, вспомогательные классы

Цели интеграционного тестирования

Поддержка интеграционного тестирования Spring преследует следующие основные цели:

  • Управлять кешированием контейнеров Spring IoC между тестами.
  • Обеспечить внедрение зависимостей экземпляров тестовых приспособлений (fixtures).
  • Обеспечить управление транзакциями, соответствующее интеграционному тестированию.
  • Предоставлять специфичные для Spring базовые классы, которые помогают разработчикам в написании интеграционных тестов.

Управление контекстом и кэширование

Spring TestContext Framework обеспечивает последовательную загрузку экземпляров Spring ApplicationContext и WebApplicationContext, а также кэширование этих контекстов. Поддержка кэширования загруженных контекстов важна, потому что время запуска может стать проблемой - не из-за накладных расходов самого Spring, а потому, что объекты, экземпляры которых создаются контейнером Spring, требуют времени для создания экземпляров. Например, для проекта с 50–100 файлами сопоставления Hibernate может потребоваться от 10 до 20 секунд для загрузки файлов сопоставления, и эти затраты перед запуском каждого теста в каждом тестовом приспособлении приводят к более медленным общим запускам тестов, что снижает производительность разработчика.

Тестовые классы обычно объявляют либо массив местоположений ресурсов для метаданных конфигурации XML или Groovy - часто в пути к классам - либо массив классов компонентов, который используется для настройки приложения. Эти расположения или классы совпадают или аналогичны тем, которые указаны в web.xml или других файлах конфигурации для производственных развертываний.

По умолчанию после загрузки настроенный ApplicationContext повторно используется для каждого теста. Таким образом, затраты на установку оплачиваются только один раз для каждого набора тестов, и последующее выполнение тестов происходит намного быстрее. В этом контексте термин "набор тестов" означает, что все тесты выполняются в одной JVM - например, все тесты выполняются из сборки Ant, Maven или Gradle для данного проекта или модуля. В том маловероятном случае, когда тест повреждает контекст приложения и требует перезагрузки (например, путем изменения определения компонента или состояния объекта приложения), инфраструктуру TestContext можно настроить для перезагрузки конфигурации и восстановления контекста приложения перед выполнением следующего теста.

Внедрение зависимостей тестовых приспособлений

Когда структура TestContext загружает контекст вашего приложения, она может дополнительно настроить экземпляры ваших тестовых классов с помощью внедрения зависимостей. Это обеспечивает удобный механизм для настройки тестовых приспособлений с использованием предварительно сконфигурированных bean-компонентов из контекста вашего приложения. Сильным преимуществом здесь является то, что вы можете повторно использовать контексты приложения в различных сценариях тестирования (например, для настройки графов объектов, управляемых Spring, транзакционных прокси, экземпляров DataSource и других), тем самым избегая необходимости дублировать настройку сложных тестовых приспособлений для индивидуальных тестовых случаев.

В качестве примера рассмотрим сценарий, в котором у нас есть класс (HibernateTitleRepository), который реализует логику доступа к данным для сущности домена Title. Мы хотим написать интеграционные тесты, проверяющие следующие области:

  • Конфигурация Spring: в принципе, все ли, что связано с конфигурацией bean-компонента HibernateTitleRepository, правильно и присутствует?
  • Конфигурация файла сопоставления Hibernate: все ли сопоставлено правильно и установлены ли правильные настройки отложенной загрузки?
  • Логика HibernateTitleRepository: работает ли настроенный экземпляр этого класса так, как ожидалось?

Управление транзакциями

Одна из распространенных проблем в тестах, которые обращаются к реальной базе данных, - это их влияние на состояние хранилища постоянных данных. Даже когда вы используете базу данных разработки, изменения состояния могут повлиять на будущие тесты. Кроме того, многие операции, такие как вставка или изменение постоянных данных, не могут быть выполнены (или проверены) вне транзакции.

Платформа TestContext решает эту проблему. По умолчанию платформа создает и откатывает транзакцию для каждого теста. Вы можете написать код, предполагающий наличие транзакции. Если вы вызываете в своих тестах объекты с транзакционным проксированием, они работают правильно в соответствии с их настроенной транзакционной семантикой. Кроме того, если метод тестирования удаляет содержимое выбранных таблиц во время выполнения транзакции, управляемой для теста, транзакция откатывается по умолчанию, и база данных возвращается в состояние, в котором она была до выполнения теста. Транзакционная поддержка предоставляется тесту с помощью bean-компонента PlatformTransactionManager, определенного в контексте приложения теста.

Если вы хотите, чтобы транзакция была зафиксирована (необычно, но иногда полезно, когда вы хотите, чтобы конкретный тест заполнял или изменял базу данных), вы можете указать инфраструктуре TestContext вызвать фиксацию транзакции вместо отката с помощью аннотации @Commit.

Классы поддержки для тестирования интеграции

Spring TestContext Framework предоставляет несколько абстрактных классов поддержки, которые упрощают написание интеграционных тестов. Эти базовые тестовые классы предоставляют четко определенные перехватчики в тестовой среде, а также удобные переменные и методы экземпляра, которые позволяют получить доступ:

  • ApplicationContext для выполнения явного поиска bean-компонентов или тестирования состояния контекста в целом.
  • JdbcTemplate для выполнения операторов SQL для запроса базы данных. Вы можете использовать такие запросы для подтверждения состояния базы данных как до, так и после выполнения кода приложения, связанного с базой данных, и Spring гарантирует, что такие запросы выполняются в рамках той же транзакции, что и код приложения. При использовании вместе с ORM-инструментом обязательно избегайте ложных срабатываний.

Кроме того, вы можете захотеть создать свой собственный суперкласс для всего приложения с переменными экземпляра и методами, специфичными для вашего проекта.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки