Якщо ти використовуєш 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 біна).