Если вы используете DependencyInjectionTestExecutionListener (который настроен по умолчанию), зависимости ваших тестовых экземпляров внедряются из бинов в контексте приложения, который вы сконфигурировали с помощью аннотации @ContextConfiguration или связанных аннотаций. Можно использовать внедрение зависимостей через сеттер, внедрение зависимостей через поле или и то, и другое, в зависимости от того, какие аннотации вы выберете и где их разместите – в сеттерах или в полях. Если вы используете JUnit Jupiter, также можно опционально использовать внедрение через конструктор (см. раздел "Внедрение зависимостей с помощью SpringExtension"). Для согласованности со средствами поддержки внедрения зависимостей на основе аннотаций Spring, также можно использовать аннотацию @Autowired или аннотацию @Inject из JSR-330 для внедрения зависимостей через поле и сеттер.
@Autowired или
@Inject для конструкторов не оказывает никакого влияния на тестовые классы.
public конструктор или сеттер в вашем тестовом классе.
Поскольку аннотация @Autowired используется для выполнения автоматического обнаружения и связывания по типу, если у вас есть несколько определений бинов одного типа, нельзя будет использовать этот подход для этих конкретных бинов. В этом случае можно использовать аннотацию @Autowired в сочетании с аннотацией @Qualifier. Также можно использовать аннотацию @Inject в сочетании с аннотацией @Named. Кроме того, если ваш тестовый класс имеет доступ к своему ApplicationContext, можно выполнить явный последовательный поиск, используя (например) вызов applicationContext.getBean("titleRepository", TitleRepository.class).
Если вам нужно, чтобы внедрение зависимостей применялось к вашим тестовым экземплярам, не аннотируйте поля или сеттеры с помощью аннотации @Autowired или аннотации @Inject. Как вариант, можно полностью отключить внедрение зависимостей, явно сконфигурировав свой класс с использованием аннотации @TestExecutionListeners и исключив DependencyInjectionTestExecutionListener.class из списка слушателей.
Рассмотрим сценарий тестирования класса HibernateTitleRepository, как описано в разделе "Цели". Следующие два листинга кода демонстрируют использование аннотации @Autowired для полей и сеттеров. Конфигурация контекста приложения представлена после всех листингов примера кода.
Логика работы внедрения зависимостей в следующих листингах кода не является специфичной для JUnit Jupiter. Те же методы внедрения зависимостей могут использоваться в сочетании с любым поддерживаемым тестовым фреймворком.
В следующих примерах вызываются статические методы с утверждением, такие как assertNotNull(), но без предварения вызова Assertions. В таких случаях предположим, что метод был надлежаще импортирован через объявление import static, которое не показано в примере.
Первый листинг кода показывает реализацию тестового класса на основе 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);
}
}
@ExtendWith(SpringExtension::class)
// определяет загружаемую конфигурацию Spring для данного тестового стенда
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {
// в этот экземпляр будет введена зависимость по типу
@Autowired
lateinit var titleRepository: HibernateTitleRepository
@Test
fun findById() {
val title = titleRepository.findById(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);
}
}
@ExtendWith(SpringExtension::class)
// определяет загружаемую конфигурацию Spring для данного тестового стенда
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {
// в этот экземпляр будет введена зависимость по типу
lateinit var titleRepository: HibernateTitleRepository
@Autowired
fun setTitleRepository(titleRepository: HibernateTitleRepository) {
this.titleRepository = titleRepository
}
@Test
fun findById() {
val title = titleRepository.findById(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">
<!-- этот бин будет внедрен в класс 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 в одном из своих сеттеров, у вас может быть несколько бинов соответствующего типа, определенных в вашем контексте приложения (например, несколько бинов DataSource ). В этом случае можно переопределить сеттер и использовать аннотацию @Qualifier для указания конкретного целевого бина, как показано ниже (но не забудьте также делегировать полномочия переопределенному методу в суперклассе):
// ...
@Autowired
@Override
public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
super.setDataSource(dataSource);
}
// ...
// ...
@Autowired
override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) {
super.setDataSource(dataSource)
}
// ...
Указанное значение квалификатора указывает на конкретный бин DataSource, предназначенного для внедрения, что сужает набор совпадений типов до конкретного бина. Его значение сопоставляется с объявлениями <qualifier> в соответствующих определениях <bean>. Имя бина используется в качестве возвратного значения квалификатора, поэтому можно должным образом указать на конкретный бин по имени (как показано ранее, предположив, что myDataSource – это id бина).
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ