Если вы используете 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
бина).
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ