【问题标题】:Overriding System property in Spring PropertyPlaceHolderConfigurer for integration testing在 Spring PropertyPlaceHolderConfigurer 中覆盖 System 属性以进行集成测试
【发布时间】:2013-07-19 02:43:46
【问题描述】:

我正在使用系统属性来定义特定于环境的属性文件的位置。但是,我想将该值覆盖为与集成测试不同的值。

这是我的生产弹簧设置。我正在使用自定义 PropertyPlaceholderConfigurer 来解析一些加密的属性文件值,但这在这里并不重要:

<-- Spring configuration in file service-spring-beans.xml -->
<bean class="com.mycompany.MyPropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:properties/${MY_ENVIRONMENT}/${MY_ENVIRONMENT}.properties</value>
        </list>
    </property>
    <property name="ignoreResourceNotFound" value="false"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>

在运行时,我们将 MY_ENVIRONMENT 的值定义为 Java 系统属性。这一切都按预期工作。但是,对于集成测试,我想将 MY_ENVIRONMENT 定义为“inttest”,因此会加载集成测试特定的属性文件 properties/inttest/inttest.properties。

我尝试使用集成测试加载的 spring 上下文来设置一个 ID 为 MY_ENVIRONMENT 的 String bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">


    <context:component-scan base-package="com.mycompany.myclasses"/>


    <bean class="java.lang.String" id="MY_ENVIRONMENT">
        <constructor-arg value="inttest"/>
    </bean>
    <!-- this imports the production spring context -->
    <import resource="classpath:service-spring-beans.xml"/>

</beans>

但是,MY_ENVIRONMENT 的值未解析,运行集成测试时出现此错误。

原因: org.springframework.beans.factory.BeanInitializationException:可以 不加载属性;嵌套异常是 java.io.FileNotFoundException:类路径资源 [properties/${MY_ENVIRONMENT}/${MY_ENVIRONMENT}.properties] 不能 因为不存在所以打开

如何在不将系统属性传递给 JVM 的情况下在测试时覆盖 MY_ENVIRONMENT?

【问题讨论】:

    标签: spring


    【解决方案1】:

    由于我使用 maven surefire 插件运行集成测试,最简单的解决方案是使用 surefire 插件配置设置系统属性,如下所示:

    <configuration>
      <systemPropertyVariables>
          <MY_ENVIRONMENT>inttest</MY_ENVIRONMENT>
       </systemPropertyVariables>
       <!-- ... -->
    <configuration>
    

    【讨论】:

      【解决方案2】:

      由于您不想使用配置文件,因此您可以创建多个上下文并只包含所需的适当上下文文件。因此,对于集成测试,您拥有 application-context.xml 和 integration-property-context.xml 文件,而在 prod 环境中,您将包含 application-context.xml 和 production-property-context.xml 文件。我已经看到这种方法大量用于在 dev 和 prod 之间切换数据源,其中 dev 将是 BasicDataSource 实现,而 prod 环境引用 JDNI 数据源。

      这种方法将帮助您避免使用 ActiveProfiles,但您会遇到管理重复 bean 的问题,这可能是 ActiveProfiles 真正简化的问题。

      【讨论】:

      • 这就是我在我的第二个应用程序上下文 XML 文件中尝试做的事情,它本身包括一个“基础”应用程序。问题是我需要覆盖基数中的一个值。
      • @lreeder 为什么它需要在base中,你不能把它移到第二个xml吗?
      • 这是我们使用的方法——实际上我们有一个案例,我们需要测试处理链中组件抛出的异常。我们使用不同的上下文文件,它们只是覆盖在自定义上下文中出错的组件。
      【解决方案3】:

      您可以考虑使用活动配置文件覆盖整个属性占位符实现。也就是说,默认(无配置文件)会启动您的属性占位符,但测试配置文件(例如“test”)可以为属性占位符创建一个新的测试 bean。

      属性占位符的一个挑战是它在应用程序上下文启动的早期阶段加载,因此普通的覆盖 bean 可能无法工作。

      【讨论】:

      • 感谢您的回复。我希望避免使用配置文件,因为我必须教育团队的其他成员使用哪个配置文件进行 int 测试,并更改我们的 CI 服务器以使用配置文件。
      • 如果您使用的是 JUnit,您可以直接在测试中指定 @ActiveProfiles(..) - 或者您是否希望避免这种情况?
      • ActiveProfiles 方法对我来说是新的,看起来是一种解决测试时配置依赖的优雅方法。我会考虑在我的下一个项目中使用它。对于这个,最简单的方法是在 maven surefire 插件中设置系统属性。
      猜你喜欢
      • 2014-12-25
      • 2014-04-22
      • 2019-10-31
      • 2015-10-28
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 2019-08-20
      • 2018-11-26
      相关资源
      最近更新 更多