Как включить AbstractContextLoaderInitializer в выполнение теста mvc?

Фон

Я конвертирую существующее приложение в использование весенних тестов веб-интеграции через MockMvcBuilders.webAppContextSetup().

У меня есть класс Initializer со следующей иерархией: hierarchy

Когда приложение запускается, этот класс автоматически обнаруживается и включается в создание контекста с помощью SpringServletContainerInitializer, и вызывается важный переопределяющий метод:

protected WebApplicationContext createRootApplicationContext() {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ConfigurableEnvironment env = ctx.getEnvironment();
    // other stuff
    env.getPropertySources().addLast(new MapPropertySource("appType", aHashMapImadeWithImportantStuff));
}

Эта проблема

Но во время выполнения фиктивного теста mvc вышеупомянутый источник свойства «appType» отсутствует. (См стопку внизу)

Вопрос

Что мне сделать, чтобы этот класс был включен в запуск теста интеграции mvc?


Стек

java.lang.IllegalStateException: Failed to load ApplicationContext

    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:91)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$null$1(ClassTestDescriptor.java:195)
    at org.junit.jupiter.engine.descriptor.JupiterTestDescriptor.executeAndMaskThrowable(JupiterTestDescriptor.java:102)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeTestInstancePostProcessors$2(ClassTestDescriptor.java:195)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeTestInstancePostProcessors(ClassTestDescriptor.java:194)
    at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$0(ClassTestDescriptor.java:186)
    at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.prepare(MethodTestDescriptor.java:120)
    at org.junit.jupiter.engine.descriptor.MethodTestDescriptor.prepare(MethodTestDescriptor.java:63)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:59)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$0(HierarchicalTestExecutor.java:88)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$0(HierarchicalTestExecutor.java:88)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:51)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:124)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:84)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.company.anApp.config.SomeConfig]; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'appType' in string value "classpath:/com/company/anApp/config/${appType}/custom.properties"
    at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:548)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:286)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:237)
    at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:539)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:286)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:237)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:196)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:279)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:237)
    at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:539)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:286)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:237)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:204)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:173)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:324)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:246)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:681)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:523)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:134)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:61)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 33 more
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'appType' in string value "classpath:/com/company/anApp/config/${appType}/custom.properties"
    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
    at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
    at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
    at org.springframework.core.env.AbstractEnvironment.resolveRequiredPlaceholders(AbstractEnvironment.java:571)
    at org.springframework.context.annotation.ConfigurationClassParser.processPropertySource(ConfigurationClassParser.java:386)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:260)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:237)
    at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:539)
    ... 58 more

person Eric Turley    schedule 27.10.2016    source источник
comment
Вероятно, связанная с этим проблема заключается в том, как включить мой существующий файл tomcat context.xml в контекст интеграционного теста. Он включает в себя свойство appType и другие вещи, такие как источник данных.   -  person Eric Turley    schedule 27.10.2016
comment
Кстати, здорово видеть, что вы используете JUnit 5 и SpringExtension. ;)   -  person Sam Brannen    schedule 28.10.2016
comment
Очень взволнован этим. Проблемы, с которыми я сталкиваюсь, связаны с запуском интеграционных тестов spring mvc - как вы говорите, вне контейнера Servlet. Есть bean-компоненты (мои, зависимости и транзитивные зависимости), которые я изо всех сил пытаюсь сделать счастливыми во время тестов.   -  person Eric Turley    schedule 03.11.2016


Ответы (1)


Как очень четко указано в справочном руководстве, Spring MVC Test Framework не выполняется в контейнере сервлетов.

Таким образом, вы просто не можете использовать файл Tomcat context.xml, web.xml или WebApplicationInitializer в сочетании с тестом MVC.

Чтобы установить свойство appType, у вас есть два варианта:

  1. Используйте @TestPropertySource
  2. Реализуйте пользовательский ApplicationContextInitializer и зарегистрируйте его через initializers в @ContextConfiguration.
person Sam Brannen    schedule 28.10.2016