Если вы используете DependencyInjectionTestExecutionListener (который настроен по умолчанию), зависимости ваших тестовых экземпляров внедряются из бинов в контексте приложения, который вы сконфигурировали с помощью аннотации @ContextConfiguration или связанных аннотаций. Можно использовать внедрение зависимостей через сеттер, внедрение зависимостей через поле или и то, и другое, в зависимости от того, какие аннотации вы выберете и где их разместите – в сеттерах или в полях. Если вы используете JUnit Jupiter, также можно опционально использовать внедрение через конструктор (см. раздел "Внедрение зависимостей с помощью SpringExtension"). Для согласованности со средствами поддержки внедрения зависимостей на основе аннотаций Spring, также можно использовать аннотацию @Autowired или аннотацию @Inject из JSR-330 для внедрения зависимостей через поле и сеттер.

В случае тестовых фреймворков, отличных от JUnit Jupiter, фреймворк TestContext не участвует в создании экземпляра тестового класса. Таким образом, использование аннотации @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 для внедрение зависимостей через поле:

Java
@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);
    }
}
Kotlin
@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 для внедрения зависимостей через сеттер, как показано ниже:

Java
@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);
    }
}
Kotlin
@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 для указания конкретного целевого бина, как показано ниже (но не забудьте также делегировать полномочия переопределенному методу в суперклассе):

Java
// ...
    @Autowired
    @Override
    public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
        super.setDataSource(dataSource);
    }
// ...
Kotlin
// ...
    @Autowired
    override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) {
        super.setDataSource(dataSource)
    }
// ...

Указанное значение квалификатора указывает на конкретный бин DataSource, предназначенного для внедрения, что сужает набор совпадений типов до конкретного бина. Его значение сопоставляется с объявлениями <qualifier> в соответствующих определениях <bean>. Имя бина используется в качестве возвратного значения квалификатора, поэтому можно должным образом указать на конкретный бин по имени (как показано ранее, предположив, что myDataSource – это id бина).