41

It doesn't seem that anything I do in Spring 4.1.17 with Spring Boot 1.2.6.RELEASE works at all. I just want to access the application properties and override them with test if necessary (without using the hack to inject a PropertySource manually)

this doesn't work..

@TestPropertySource(properties = {"elastic.index=test_index"})

nor does this..

@TestPropertySource(locations = "/classpath:document.properties")

nor this..

@PropertySource("classpath:/document.properties")

full test case..

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@TestPropertySource(properties = {"elastic.index=test_index"})
public class PropertyTests {
    @Value("${elastic.index}")
    String index;

    @Configuration
    @TestPropertySource(properties = {"elastic.index=test_index"})
    static class ContextConfiguration {
    }

    @Test
    public void wtf() {
        assertEquals("test_index", index);
    }
}

resulting in

org.junit.ComparisonFailure: 
Expected :test_index
Actual   :${elastic.index}

It seems there is a lot of conflicting information between 3.x and 4.x and I can't find anything that will work for sure.

Any insight would be gratefully appreciated. Cheers!

oberlies
  • 11,503
  • 4
  • 63
  • 110
Thomas Beauvais
  • 1,546
  • 2
  • 16
  • 30
  • `TestPropertySource` works. – Alex78191 Apr 09 '18 at 18:41
  • TestPropertySource does not override environment variables as it should according to https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html – Alex Worden Apr 20 '18 at 23:17
  • 1
    Spring boot provides the annotation @SpringBootTest which can be used to read the config yml. Please check here for details : https://stackoverflow.com/a/50309219/1169093 – denzal May 12 '18 at 18:08

7 Answers7

17

Turns out the best way (until Spring fixes this oversight) is to a PropertySourcesPlaceholderConfigurer that will bring in test.properties (or whatever you want) and @Import or extend that @Configuration.

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;

@Configuration
public class PropertyTestConfiguration {
    @Bean
    public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() throws IOException {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        ppc.setLocations(ArrayUtils.addAll(
                        new PathMatchingResourcePatternResolver().getResources("classpath*:application.properties"),
                        new PathMatchingResourcePatternResolver().getResources("classpath*:test.properties")
                )
        );

        return ppc;
    }

}

This allows you to define defaults in application.properties and override them in test.properties. Of course, if you have multiple schemes, then you can configure the PropertyTestConfiguration class as necessary.

And use this in a unit test.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class PropertyTests {
    @Value("${elastic.index}")
    String index;

    @Configuration
    @Import({PropertyTestConfiguration.class})
    static class ContextConfiguration {
    }
}
Thomas Beauvais
  • 1,546
  • 2
  • 16
  • 30
  • All you really need is a `PropertySourcesPlaceholderConfigurer` in your application context, then the `@PropertySource` will work. – FelixM Jan 02 '19 at 16:16
  • You can do this in your `@Configuration` class (formatting doesn't work here): public @Bean PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } – FelixM Apr 01 '19 at 13:05
16

I used the locations property of @TestPropertySource to override (or add) properties.

This worked for me (spring 4.2.4):

@TestPropertySource(locations = {
   "classpath:test.properties",
   "classpath:test-override.properties" })

But overriding properties like below didn't:

@TestPropertySource(
  locations = {"classpath:test.properties"},
  properties = { "key=value" })

Even though the javadoc says that those properties have highest precedence. A bug maybe?

Update

The bug should be fixed in Spring boot version 1.4.0 and up. See the commit which closes the issue. By now, properties declared in the presented way should get precedence.

GreenGiant
  • 4,930
  • 1
  • 46
  • 76
sorrymissjackson
  • 2,395
  • 1
  • 19
  • 18
  • 2
    Indeed seems like a bug: https://jira.spring.io/browse/SPR-14068 https://github.com/spring-projects/spring-boot/issues/4828 – eis Oct 21 '16 at 15:04
  • 2
    This worked for me as well in Spring 2.5.7. Please note however that it does not work for YAML files because they're evidently not supported (ref: comment by @Sym-Sym [here](https://stackoverflow.com/questions/38711871/load-different-application-yml-in-springboot-test)) – Asa Feb 12 '22 at 18:28
12

Your use of @Value requires a PropertySourcesPlaceholderConfigurer bean to resolve ${...} placeholders. See the accepted answer here: @Value not set via Java-configured test context

Community
  • 1
  • 1
Don Bottstein
  • 1,640
  • 13
  • 17
  • 1
    Right, the question is why? This seems like a huge oversight. Why did this feature go away? Anyway.. if this is the only way.. then so be it.. though @TestPropertySource should work.. – Thomas Beauvais Sep 17 '15 at 19:32
  • @Don Bottstein: Could you please highlight the Sources part of PropertySourcesPlaceholderConfigurer, as i suppose a lot of people like myself overlook the part, when they already have a PropertyPlaceholderConfigurer available, which is not enough. – realsim Mar 18 '16 at 15:45
7

If you have this problem and you're trying with yaml as properties file keep in mind that spring @TestPropertySource and @PropertySource doesn't work with yaml file, and properties won't be loaded properly.

https://github.com/spring-projects/spring-boot/issues/10772#issuecomment-339581902

goldlil
  • 71
  • 1
  • 5
4

For Me @TestPropertySource("classpath:xxxxxxxx.properties") worked

Swarit Agarwal
  • 2,520
  • 1
  • 26
  • 33
3

Have you tried using @PropertySource("classpath:document.properties") or @PropertySource("classpath*:document.properties") ?

user2004685
  • 9,548
  • 5
  • 37
  • 54
0

I had issue with @TestPropertySource. test.properties not found

below is the one before fixed

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ExtContext.class)
@TestPropertySource(locations = "classpath: test.properties")

i removed space between classpath: and test.properties as below

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ExtContext.class)
@TestPropertySource(locations = "classpath:test.properties")

This worked for me, When test.properties is not found in classpth. misht work for you aswell