Передача поля свойств с использованием аннотации @value в фиктивный метод имеет значение null

Я не могу передать поле, прочитав файл application-test.properties из теста в тестовый метод.

@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
public class ReportImplTest {
    @Mock
    private Dependencies dependencies;

    @InjectMocks
    private ReportImplTest  underTest;

   @Test
    public void testgetReports() {
         List<String> reps= underTest.getReports(anyString());
    }

}

Вот фактический класс издеваемого метода

@Component
public class ReportImpl {

    @Value("${REP_PROPNAME}")
    String reppropname;

    public List<String> getReports(String rep){

      return staticUtilityclass.process(staticUtilityclass.transform(reppropname,"Reports"));
    }

}

reppropname принимает значение null в методе getReports. Тест выполняется в контексте теста, где класс ReportImpl будет в контексте приложения. Есть ли способ узнать стоимость reppropname. Пробовал использовать @ContextConfiguration (@ContextConfiguration(classes = {ApplicaitonBootStarter.class)} он работает, но загружает все компоненты и зависимости. Есть ли другой способ получить имя реппропа?

Это было бы намного проще, если бы вместо этого вы использовали внедрение конструктора; вам вообще не понадобится Spring для теста.

chrylis -cautiouslyoptimistic- 04.11.2018 05:39

@chrylis вы имеете в виду вместо инъекции поля с использованием аннотации значений? не могли бы вы пролить больше света

krthk 04.11.2018 06:13

Вы можете поместить @Value в параметр метода, и Spring с радостью настроит конструкторы autowire.

chrylis -cautiouslyoptimistic- 04.11.2018 06:19

@chrylis не работает, так как reppropname используется в статическом методе.

krthk 04.11.2018 07:14

Тогда показанный вами класс не будет компилироваться. (Ответ, конечно, «передать как параметр».)

chrylis -cautiouslyoptimistic- 04.11.2018 16:04

Ваш тест практически бесполезен, поскольку ничего не делает. Он загружает конфигурацию пружины и после этого игнорирует ее. С обычным приложением Spring @Mock и @InjectMocks также будут null, и ваш тест провалится (тот факт, что он работает, заставляет меня задуматься, не используете ли вы Spring Boot). ReportImpl не управляется Spring, поскольку @InjectMocks создает новый экземпляр вне Spring, и поэтому @Value не будет обрабатываться. Так что просто вставьте экземпляр из контекста приложения. Да, он загрузит все, но только один раз и кеширует все для последующих тестов.

M. Deinum 05.11.2018 08:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
6
1 099
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой значение здесь не вводится, заключается в том, что вы не предоставляете конфигурацию своему тестовому классу. Spring просто не знает, как построить ваш bean-компонент. Итак, как вы упомянули, вы должны аннотировать тестовый класс с помощью @ContextConfiguration. Если вы не хотите создавать весь контекст со всеми bean-компонентами, вы можете создать тестовую конфигурацию и предоставить там только необходимые bean-компоненты.

@Configuration //can be as well annotated with @TestConfiguration
@ComponentScan("package.to.scan")
public class TestConfiguration {
}

А теперь предоставьте этот класс вашему тесту

@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
@ContextConfiguration(classes = TestConfiguration.class)
public class ReportImplTest {
........
}

Но есть еще один момент. Предполагая, что у вас есть метод @Before, который выполняет MockitAnnotations.initMocks(this);, тестируемый объект по-прежнему объявлен только с @InjectMocks. Что это значит? Это означает, что если вы не инициализируете этот объект самостоятельно, mockito позаботится об этом и инициализируется с использованием доступного конструктора, и в этом случае spring не будет вводить аннотированное поле @Value. Что вам нужно сделать, так это аннотировать тестируемый объект с помощью @Autowired, чтобы Spring инициализировал его до того, как mockito попытается о нем позаботиться:

@InjectMocks
@Autowired
private ReportImplTest  underTest;

Другие вопросы по теме