lreeder
lreeder

Reputation: 12206

Overriding System property in Spring PropertyPlaceHolderConfigurer for integration testing

I'm using a System property to define the location for an environment-specific properties file. However, I would like to override that value to something different for integration tests.

Here's my production spring setup. I'm using a custom PropertyPlaceholderConfigurer to resolve some encrypted property file values, but that's not important here:

<-- 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>

At runtime, we define the value of MY_ENVIRONMENT as a Java system property. This all works as expected. However, for integration tests, I would like to define MY_ENVIRONMENT as "inttest", so the integration-test specific property file properties/inttest/inttest.properties is loaded.

I've tried to use a spring context loaded by the integration-test to set up a String bean with the id MY_ENVIRONMENT:

<?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>

However, the value of MY_ENVIRONMENT is not resolved , and I get this error when running the integration tests.

Caused by: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [properties/${MY_ENVIRONMENT}/${MY_ENVIRONMENT}.properties] cannot be opened because it does not exist

How can I override MY_ENVIRONMENT at inttest time without passing a System property to the JVM?

Upvotes: 1

Views: 3624

Answers (3)

lreeder
lreeder

Reputation: 12206

Since I was using the maven surefire plugin to run integration tests, the simplest solution turned out to be setting the system property using the surefire plugin configuration, like this:

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

Upvotes: 3

Joe
Joe

Reputation: 1023

Since you don't want to use profiles, you can create multiple contexts and just include the proper context files for what you want. So for integration testing you have have your application-context.xml and an integration-property-context.xml file while, in the prod environment you would include the application-context.xml with a production-property-context.xml file. I've seen this approach used heavily to switch datasources between dev and prod where dev would be a BasicDataSource implementation and the prod environment references a JDNI DataSource.

This approach will help you avoid ActiveProfiles, but you run in to the problem of managing duplicate beans possibly which ActiveProfiles really simplified down.

Upvotes: 2

incomplete-co.de
incomplete-co.de

Reputation: 2137

you could look at overriding your whole property placeholder implementation using active profiles. that is, the default (no profile) launches your property placeholder, but a test profile (e.g. 'test') could create a new test bean for the property placeholder.

one of the challenges with property placeholder is that its loaded at the very early stages of the application context startup, so a normal override bean may not work.

Upvotes: 1

Related Questions