Интеграционное тестирование в Spring: TestContext Framework, иерархии контекстов

При написании интеграционных тестов, основанных на загруженном Spring ApplicationContext, часто бывает достаточно тестирования в одном контексте. Однако бывают случаи, когда полезно или даже необходимо протестировать иерархию экземпляров ApplicationContext. Например, если вы разрабатываете веб-приложение Spring MVC, у вас обычно есть корневой WebApplicationContext, загруженный Spring ContextLoaderListener, и дочерний WebApplicationContext, загруженный Spring DispatcherServlet. Это приводит к иерархии родительско-дочернего контекста, в которой общие компоненты и конфигурация инфраструктуры объявляются в корневом контексте и используются в дочернем контексте веб-компонентами. Другой вариант использования можно найти в приложениях Spring Batch, где у вас часто есть родительский контекст, который обеспечивает конфигурацию для разделяемой пакетной инфраструктуры, и дочерний контекст для конфигурации определенного пакетного задания.

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

Примеры на основе JUnit Jupiter в этом разделе показывают общие сценарии конфигурации для интеграционных тестов, которые требуют использования контекстных иерархий.

Единый тестовый класс с контекстной иерархией

ControllerIntegrationTests представляет собой типичный сценарий тестирования интеграции для веб-приложения Spring MVC, объявляя иерархию контекста, состоящую из двух уровней: один для корневого WebApplicationContext (загружается с помощью TestAppConfig @Configuration класса) и один для сервлета диспетчера WebApplicationContext (загружается с помощью WebConfig @Configuration класса). Контекст WebApplicationContext, который автоматически подключается к экземпляру теста, является контекстом дочернего (то есть самым нижним контекстом в иерархии). В следующем листинге показан этот сценарий конфигурации:

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextHierarchy({
    @ContextConfiguration(classes = TestAppConfig.class),
    @ContextConfiguration(classes = WebConfig.class)
})
class ControllerIntegrationTests {

    @Autowired
    WebApplicationContext wac;

    // ...
}

Иерархия классов с неявным родительским контекстом

Тестовые классы в этом примере определяют иерархию контекста в иерархии тестовых классов. AbstractWebTests объявляет конфигурацию корневого контекста WebApplicationContext в веб-приложении на основе Spring. Однако обратите внимание, что AbstractWebTests не объявляет @ContextHierarchy. Следовательно, подклассы AbstractWebTests могут при желании участвовать в иерархии контекста или следовать стандартной семантике для @ContextConfiguration. SoapWebServiceTests и RestWebServiceTests расширяют AbstractWebTests и определяют иерархию контекста с помощью @ContextHierarchy. В результате загружаются три контекста приложения (по одному для каждого объявления @ContextConfiguration), и контекст приложения, загружаемый на основе конфигурации в AbstractWebTests, устанавливается в качестве родительского контекста для каждого из контекстов, загруженных для конкретных подклассов. В следующем листинге показан этот сценарий конфигурации:

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public abstract class AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml"))
public class SoapWebServiceTests extends AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}

Иерархия классов с объединенной конфигурацией иерархии контекстов

Классы в этом примере показывают использование именованных уровней иерархии для объединения конфигурации для определенных уровней в иерархии контекста. BaseTests определяет два уровня в иерархии: родительский и дочерний (parent и child). ExtendedTests расширяет BaseTests и инструктирует Spring TestContext Framework объединить конфигурацию контекста для дочернего уровня иерархии, гарантируя, что имена, объявленные в атрибуте name в @ContextConfiguration, являются дочерними. В результате загружаются три контекста приложения: один для /app-config.xml, один для /user-config.xml и один для {"/user-config.xml", "/order-config.xml"} . Как и в предыдущем примере, контекст приложения, загруженный из /app-config.xml, устанавливается как родительский контекст для контекстов, загруженных из /user-config.xml и {"/user-config.xml", "/order-config.xml "}. В следующем листинге показан этот сценарий конфигурации:

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
    @ContextConfiguration(name = "parent", locations = "/app-config.xml"),
    @ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
    @ContextConfiguration(name = "child", locations = "/order-config.xml")
)
class ExtendedTests extends BaseTests {}

Иерархия классов с переопределенной конфигурацией иерархии контекста

В отличие от предыдущего примера, этот пример демонстрирует, как переопределить конфигурацию для данного именованного уровня в иерархии контекста, установив для флага inheritLocations в @ContextConfiguration значение false. Следовательно, контекст приложения для ExtendedTests загружается только из /test-user-config.xml, а его родительский контекст установлен в контекст, загруженный из /app-config.xml. В следующем листинге показан этот сценарий конфигурации:

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
    @ContextConfiguration(name = "parent", locations = "/app-config.xml"),
    @ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
    @ContextConfiguration(
        name = "child",
        locations = "/test-user-config.xml",
        inheritLocations = false
))
class ExtendedTests extends BaseTests {}

Загрязнение контекста внутри контекстной иерархии

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


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


Комментарии

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

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

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

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