20

I've got a Maven project which uses Java-configured Spring (@Configuration etc.). Properties which are referenced by @Value are stored in different places, e.g. Tomcat's context.xml.

For testing I've created a .properties file to provide some values for the components and services. In my JUnit test (which uses a spring test context) this .properties file is added via @PropertySource. The problem is that the values will not be loaded from the file, instead the value identifier is set as value, e.g. ${someFlag:false} (so I get ClassCastExceptions for any other than String). Also the default value will not be set, so I think, the values won't be processed at all.

I'm sure Spring finds this file because when I change the value of @PropertySource I get some FileNotFoundException. Nevertheless I've tried different variants to point to this file an all have worked (tested by renaming which produced FileNotFoundException):

  • classpath:/test.properties (my preferred notation)
  • /test.properties
  • file:src/test/resources/test.properties

I'm also sure that Spring itself works, because when I remove the @Value, the class under test is injected via @Autowired in my test as expected.

Down below you'll find the problem scenario stripped down as much as possible. For versions and dependencies please see the pom.xml at the bottom.

MyService.java

package my.package.service;

// Imports

@Service
public class MyService {

    @Value("${someFlag:false}")
    private Boolean someFlag;

    public boolean hasFlag() {
        return BooleanUtils.isTrue(someFlag);
    }
}

MyConfiguration.java

@Configuration
@ComponentScan(basePackages = {"my.package.service"})
public class MyConfiguration {
}

MyServiceComponentTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyTestConfiguration.class})
public class MyServiceComponentTest {

    @Autowired
    private MyService service;

    @Test
    public void hasFlagReturnsTrue() {
        assertThat(service.hasFlag(), is(true));
    }
}

MyTestConfiguration.java

@Configuration
@Import({MyConfiguration.class})
@PropertySource("classpath:/test.properties")
public class MyTestConfiguration {
}

src/test/resources/test.properties

someFlag=true

pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>3.2.3.RELEASE</spring.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- Test dependencies -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-library</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
</dependencies>

3 Answers 3

29

The issue here is you need a PropertySourcesPlaceholderConfigurer also which is actually responsible for resolving the ${..} fields, just add another bean which creates this bean:

@Bean
public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
    return new PropertySourcesPlaceholderConfigurer();
}
Sign up to request clarification or add additional context in comments.

4 Comments

See the javadoc for PropertySource, see Resolving ${...} placeholders in <bean> and @Value annotations
Also, see the answer here. A PropertySourcesPlaceHolderConfigurer is a BeanFactoryPostProcessor.
It may work in some situations if Spring generates some beans after your propertiesResolver() is called, but it will fail otherwise. To make sure it works, you need to make it static.
When using XML, this will work This happens automatically when using <context:property-placeholder> in XML docs.spring.io/spring-framework/docs/3.2.x/javadoc-api/org/…
3

With Spring 4, it's now possible to use TestPropertySource:

@TestPropertySource(value="classpath:/config/test.properties")

In order to load specific properties for a junit test

3 Comments

can you expand your comment?
I have tested @TestPropertySource together with @Value and properties were not loaded...
you need also to follow Biju's answer.
2

In addition to Biju Kunjummen answer:

If you use @ConfigurationProperties to inject properties into bean setters, then ConfigurationPropertiesBindingPostProcessor need to be created (instead of PropertySourcesPlaceholderConfigurer):

@Configuration
static class PropertyConfig {
    @Bean
    public static ConfigurationPropertiesBindingPostProcessor propertiesProcessor() {
        return new ConfigurationPropertiesBindingPostProcessor();
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.