Можно ли параметризовать тест JUnit Jupiter с помощью bean-компонентов из Spring ApplicationContext?

Я хотел бы написать модульный тест, который выполняется для каждого компонента Spring заданного типа. Параметризованные тесты JUnit5 предлагают множество возможностей, но я не знаю, как внедрить bean-компоненты в источник метода, поскольку это должен быть статический метод.

Есть ли способ определить параметры теста JUnit5 на основе контекста приложения Spring?


person Oliver    schedule 26.06.2019    source источник
comment
Вы можете просто ввести контекст и использовать имена Spring Bean в качестве параметров и выполнить поиск в каком-то коде установки.   -  person markusw    schedule 26.06.2019
comment
Но имена компонентов должны быть статическим списком?   -  person Oliver    schedule 26.06.2019


Ответы (2)


Во-первых, фабричный метод, настроенный через @MethodSource, не обязательно должен быть static. Второе предложение в Руководстве пользователя объясняет это.

Фабричные методы в тестовом классе должны быть static, если только тестовый класс не помечен @TestInstance(Lifecycle.PER_CLASS); тогда как фабричные методы во внешних классах всегда должны быть static.

Таким образом, если вы используете семантику @TestInstance(PER_CLASS), ваш фабричный метод @MethodSource может быть нестатическим и, следовательно, может обращаться к ApplicationContext, внедренному в тестовый экземпляр.

Вот пример, который демонстрирует это для bean-компонентов типа String с преднамеренной ошибкой для bean-компонента bar.

import java.util.stream.Stream;

import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;

@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {

    @Autowired
    ApplicationContext applicationContext;

    @ParameterizedTest
    @MethodSource
    void stringBeans(String bean) {
        assertEquals(3, bean.length());
    }

    Stream<String> stringBeans() {
        return applicationContext.getBeansOfType(String.class).values().stream();
    }

    @Configuration
    static class Config {

        @Bean
        String foo() {
            return "foo";
        }

        @Bean
        String bar() {
            return "barf";
        }
    }
}

Если вы не хотите работать напрямую с ApplicationContext, вы можете упростить решение, введя коллекцию всех таких bean-компонентов заданного типа (String в этом примере) напрямую, как показано ниже.

@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {

    @Autowired
    List<String> stringBeans;

    @ParameterizedTest
    @MethodSource
    void stringBeans(String bean) {
        assertEquals(3, bean.length());
    }

    Stream<String> stringBeans() {
        return this.stringBeans.stream();
    }

    @Configuration
    static class Config {

        @Bean
        String foo() {
            return "foo";
        }

        @Bean
        String bar() {
            return "barf";
        }
    }
}
person Sam Brannen    schedule 26.06.2019

Использование @TestFactory может помочь.

На самом деле я наткнулся на сообщение, в котором делается очень похожее (или то же самое), что и вы на github.

Пусть ваш тест запускается с SpringExtenion и использует внедренные компоненты Bean в качестве параметров для нашего теста.

person markusw    schedule 26.06.2019