【问题标题】:Spring boot not resolving custom properties from application.properties during integration testsSpring Boot 在集成测试期间未从 application.properties 解析自定义属性
【发布时间】:2015-12-19 14:19:36
【问题描述】:

我的Spring Boot测试配置如下:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {TestEnd2EndIntegrationConfiguration.class})
@WebAppConfiguration
@ActiveProfiles(Profiles.TEST)//=="test"
@Transactional
public abstract class AbstractEnd2EndIntegrationTest {

}

然后从 application-test.properties 我有以下 custom 属性:

database.hibernate.dialect=org.hibernate.dialect.H2Dialect
database.hibernate.hbm2ddl.auto=create
database.hibernate.logSqlInfo=true

我使用如下:

@Value("${database.hibernate.dialect}")
private String hibernateDialect;

但是,自定义属性未解析,我得到以下异常:

com.bignibou.it.controller.signup.SignupRestControllerTest > shouldRejectUnavailableEmailAddress FAILED
    java.lang.IllegalStateException
        Caused by: org.springframework.beans.factory.BeanCreationException
            Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException

编辑

这是我的 gradle 配置:

 sourceSets {

        main {
            output.resourcesDir = output.classesDir
        }

        integrationTest {
            java.srcDirs = ['src/it/java']
            resources.srcDirs = ['src/it/resources', 'src/main/resources']
            compileClasspath = sourceSets.main.output + configurations.testRuntime
            runtimeClasspath = output + compileClasspath
        }
    }

   task integrationTest(type: Test) {
        description "Run the integration tests."
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
        reports.html.destination = file("$reports.html.destination/integration")
        reports.junitXml.destination = file("$reports.junitXml.destination/integration")
    }

编辑 2

当我从 IDE (intellij) 运行测试时,我得到一个不同的错误:

ava:342)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:273)
    at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:103)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 36 more

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:183)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:123)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:217)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:276)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:278)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ClassCastException: org.springframework.boot.context.config.ConfigFileApplicationListener$ConfigurationPropertySources cannot be cast to org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor$ConfigurationPropertySources
    at org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor$ConfigurationPropertySources.finishAndRelocate(ConfigFileEnvironmentPostProcessor.java:528)
    at org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor$PropertySourceOrderingPostProcessor.reorderSources(ConfigFileEnvironmentPostProcessor.java:239)
    at org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor$PropertySourceOrderingPostProcessor.postProcessBeanFactory(ConfigFileEnvironmentPostProcessor.java:235)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:131)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:673)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:519)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:667)
    at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:342)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:273)
    at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:103)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 36 more

编辑 3

这是来自 Gradle 集成测试的详细原因

Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [${database.hibernate.ejb.naming_strategy}] as strategy [org.hibernate.cfg.NamingStrategy]
    at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:128)
    at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:155)
    at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveStrategy(StrategySelectorImpl.java:136)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.processProperties(EntityManagerFactoryBuilderImpl.java:925)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:840)
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)

编辑 4:来自以下调试:EntityManagerFactoryBuilderImpl

configurationValues = {HashMap@4101}  size = 14
 0 = {HashMap$Node@4092} "hibernate.format_sql" -> "${database.hibernate.logSqlInfo}"
 1 = {HashMap$Node@4096} "hibernate.use_sql_comments" -> "${database.hibernate.logSqlInfo}"
 2 = {HashMap$Node@4107} "javax.persistence.nonJtaDataSource" -> 
 3 = {HashMap$Node@4108} "hibernate.hbm2ddl.auto" -> "${database.hibernate.hbm2ddl.auto}"
 4 = {HashMap$Node@4109} "javax.persistence.sharedCache.mode" -> "ENABLE_SELECTIVE"
 5 = {HashMap$Node@4110} "hibernate.dialect" -> "${database.hibernate.dialect}"
 6 = {HashMap$Node@4111} "hibernate.ejb.naming_strategy" -> "${database.hibernate.ejb.naming_strategy}"
 7 = {HashMap$Node@4112} "hibernate.cache.use_second_level_cache" -> "${database.hibernate.cache.use_second_level_cache}"
 8 = {HashMap$Node@4113} "hibernate.ejb.persistenceUnitName" -> "default"
 9 = {HashMap$Node@4114} "hibernate.connection.charSet" -> "${database.hibernate.connection.charSet}"
 10 = {HashMap$Node@4115} "hibernate.show_sql" -> "${database.hibernate.logSqlInfo}"
 11 = {HashMap$Node@4116} "hibernate.cache.region.factory_class" -> "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"
 12 = {HashMap$Node@4117} "hibernate.generate_statistics" -> "${database.hibernate.generate_statistics}"
 13 = {HashMap$Node@4118} "javax.persistence.validation.mode" -> "AUTO"

可以看到属性没有展开……这是为什么呢?

【问题讨论】:

  • application-test.properties 驻留在哪里(例如,src/test/resources)?
  • 你是如何执行测试的:Eclipse、IDEA、Maven、Gradle?
  • 嗨,山姆! application-test.properties 位于 src/main/resourcesapplication.properties 中,我的 Spring Boot 测试也没有发现。我将./gradlew integrationTest 与自定义集成测试任务一起使用。
  • 在IDE中运行测试是否有效?
  • 不,它也不起作用。我已经编辑了我的帖子(参见上面的编辑 2)。

标签: spring hibernate spring-boot spring-test


【解决方案1】:

您需要 3 件事来让您的属性在集成测试类中自动装配:

  1. PropertySource 注释。看起来你错过了那个。 您可以在抽象集成测试类中添加类似的内容:
@PropertySource(value= {"classpath:*.properties"})
  1. 属性文件必须在您的类路径中。我建议为测试和集成测试属性添加一个单独的文件夹。在src/main 中创建一个integration-test-resources 目录并将您的属性文件复制到其中,然后配置您的构建管理器以将它们添加为类路径资源。

这是一个如何在 Gradle 中执行此操作的示例:

sourceSets {
  integrationTest {
     resources {
       srcDir "integration-test-resources"
     }
  }
}
  1. 使用@Value 注释您的属性。看起来您已经在这样做了。

【讨论】:

    【解决方案2】:

    问题实际上在于以下代码行:

    @SpringApplicationConfiguration(classes = {TestEnd2EndIntegrationConfiguration.class})
    

    TestEnd2EndIntegrationConfiguration 不是带有 main 的 Spring Boot 应用程序,最重要的是它没有使用 @EnableAutoConfiguration 注释。

    我改成:

    @Configuration
    @EnableAutoConfiguration(exclude = {
            ManagementWebSecurityAutoConfiguration.class,
            ...
            MailSenderAutoConfiguration.class
    })
    @ComponentScan(basePackages = {"com.bignibou.configuration", "com.bignibou.it.configuration"})
    public class TestApplication {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(TestApplication.class, args);
        }
    }
    

    还有我的抽象测试类:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = {TestApplication.class})//Notice the change
    @WebAppConfiguration
    @ActiveProfiles(Profiles.TEST)
    @Transactional
    public abstract class AbstractIntegrationTest {
    
    }
    

    现在测试作为 Spring Boot 应用程序运行,application.properties 中的自定义属性也已解决。

    【讨论】:

    • 我假设你的 TestEnd2EndIntegrationConfiguration 类被 @EnableAutoConfiguration 注释。对不起,我没有在这方面询问,但我很高兴你知道了! ;)
    • 仅供参考:TestApplication 不需要 main 方法。这只是从命令行启动应用程序所必需的。
    • 好的。谢谢(你的)信息。没有主线实际上更有意义!
    • @balteo,您不需要 @SpringApplicationConfiguration 进行集成测试,您可以简单地使用 @ContextConfiguration 并像这样指定所有配置类:@ContextConfiguration(classes = {Application.class, SecurityConfig.class, MVCConfig.class, PersistenceConfig.class})
    【解决方案3】:

    如果您想将 Hibernate 属性放在 application-${profile}.properties 中,我认为您应该使用 spring.jpa.hibernate.dll-auto,即 Spring 属性文件。

    同样,应该使用spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

    我使用带有这种配置的 Spring Boot,我从来不需要任何 @PropertySource 注释。

    【讨论】:

      猜你喜欢
      • 2014-12-11
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-29
      • 2019-08-20
      • 2016-02-20
      • 1970-01-01
      • 2018-11-14
      相关资源
      最近更新 更多