Интеграционное тестирование в Spring: TestContext Framework, внедрение зависимостей тестовых приспособлений
Когда вы используете DependencyInjectionTestExecutionListener (который настроен по умолчанию), зависимости ваших тестовых экземпляров вводятся из bean-компонентов в контексте приложения, который вы настроили с помощью @ContextConfiguration или связанных аннотаций. Вы можете использовать внедрение сеттера, внедрение поля или и то, и другое, в зависимости от того, какие аннотации вы выбираете и размещаете ли вы их в методах или полях установщика. Если вы используете JUnit Jupiter, вы также можете дополнительно использовать внедрение конструктора (внедрение зависимостей с помощью SpringExtension). Для обеспечения согласованности с поддержкой Spring на основе аннотаций вы также можете использовать аннотацию Spring @Autowired или аннотацию @Inject из JSR-330 для внедрения полей и установщиков.
Для фреймворков тестирования, отличных от JUnit Jupiter, TestContext framework не участвует в создании экземпляра тестового класса. Таким образом, использование @Autowired или @Inject для конструкторов не влияет на тестовые классы.
Хотя в производственном коде внедрение в поле не поощряется, в тестовом коде внедрение в поле на самом деле вполне естественно. Разница объясняется тем, что вы никогда не создадите экземпляр своего тестового класса напрямую. Следовательно, нет необходимости вызывать общедоступный конструктор или метод установки в вашем тестовом классе.
Поскольку @Autowired используется для выполнения автоматического подключения по типу, если у вас есть несколько определений bean-компонентов одного типа, вы не можете полагаться на этот подход для этих конкретных bean-компонентов. В этом случае вы можете использовать @Autowired вместе с @Qualifier. Вы также можете использовать @Inject вместе с @Named. В качестве альтернативы, если ваш тестовый класс имеет доступ к своему ApplicationContext, вы можете выполнить явный поиск, используя (например) вызов applicationContext.getBean("titleRepository", TitleRepository.class).
Если вы не хотите, чтобы инъекция зависимостей применялась к вашим тестовым экземплярам, не аннотируйте поля или методы установки с помощью @Autowired или @Inject. Кроме того, вы можете полностью отключить внедрение зависимостей, явно настроив свой класс с помощью @TestExecutionListeners и исключив DependencyInjectionTestExecutionListener.class из списка слушателей.
Рассмотрим сценарий тестирования класса HibernateTitleRepository. Следующие два листинга кода демонстрируют использование @Autowired для полей и методов установки. Конфигурация контекста приложения представлена после всех примеров кода.
Поведение внедрения зависимостей в следующих листингах кода не относится к JUnit Jupiter. Те же методы DI можно использовать в сочетании с любым поддерживаемым фреймворком тестирования.
В следующих примерах выполняются вызовы статических методов утверждения, например assertNotNull(), но без добавления к вызову Assertions. В таких случаях предполагаем, что метод был правильно импортирован через статическое объявление импорта, которое не показано в примере.
В первом листинге кода показана реализация тестового класса на основе JUnit Jupiter, который использует @Autowired для внедрения поля:
@ExtendWith(SpringExtension.class)
// указывает конфигурацию Spring для загрузки
// для этой тестовой фикстуры
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {
// этот экземпляр будет зависимостью, внедренной по типу
@Autowired
HibernateTitleRepository titleRepository;
@Test
void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}
В качестве альтернативы вы можете настроить класс для использования @Autowired для внедрения установщика следующим образом:
@ExtendWith(SpringExtension.class)
// указывает конфигурацию Spring для загрузки
// для этой тестовой фикстуры
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {
// этот экземпляр будет зависимостью, внедренной по типу
HibernateTitleRepository titleRepository;
@Autowired
void setTitleRepository(HibernateTitleRepository titleRepository) {
this.titleRepository = titleRepository;
}
@Test
void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}
В приведенных выше листингах кода используется тот же файл контекста XML, на который ссылается аннотация @ContextConfiguration (то есть repository-config.xml). Ниже показана эта конфигурация:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- этот bean-компонент будет внедрен в класс HibernateTitleRepositoryTests -->
<bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- конфигурация опущена для краткости -->
</bean>
</beans>
Если вы расширяетесь из предоставленного Spring базового класса тестирования, который использует @Autowired в одном из своих методов установки, у вас может быть несколько bean-компонентов затронутого типа, определенных в контексте вашего приложения (например, несколько bean-компонентов DataSource). В таком случае вы можете переопределить метод установки и использовать аннотацию @Qualifier, чтобы указать конкретный целевой bean-компонент, как показано ниже (но обязательно делегируйте переопределенный метод в суперклассе):
// ...
@Autowired
@Override
public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
super.setDataSource(dataSource);
}
// ...
Указанное значение квалификатора указывает конкретный bean-компонент DataSource для внедрения, сужая набор соответствий типов до конкретного bean-компонента. Его значение сопоставляется с объявлениями <qualifier> в соответствующих определениях <bean>. Имя bean-компонента используется в качестве значения квалификатора, поэтому вы также можете эффективно указать на конкретный bean-компонент по имени (как показано ранее, предполагая, что myDataSource является идентификатором bean-компонента).
Читайте также:
- Интеграционное тестирование в Spring: TestContext Framework, загрузка WebApplicationContext
- Интеграционное тестирование в Spring: TestContext Framework, кэширование контекста
- Интеграционное тестирование в Spring: TestContext Framework, иерархии контекстов
Комментарии
Отправить комментарий