22

I am using @TestPropertySource to overwrite application.yml properties in my integration test for a spring boot app.

@TestPropertySource(properties = { "repository.file.path=src/test/resources/x" })

I was wondering if there was some way to make the property VALUE dynamic. Something like this:

 @TestPropertySource(properties = { "repository.file.path=PropertyValueProvider.class" })

Your feedback is appreciated. In my case the property value is system specific that should be generated upon the test run.

Vladimir
  • 1,120
  • 2
  • 11
  • 18

3 Answers3

27

@TestPropertySource only provides declarative mechanisms for configuring PropertySources. Documentation in Spring Reference Manual.

If you need programmatic support for adding a PropertySource to the Environment, you should implement an ApplicationContextInitializer which can be registered via @ContextConfiguration(initializers = ...). Documentation in Spring Reference Manual.

Regards,

Sam (author of the Spring TestContext Framework)

Oliver Drotbohm
  • 80,157
  • 18
  • 225
  • 211
Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • 11
    I found [this example](https://github.com/spring-projects/spring-boot/blob/8dd1354d82be9bae236e3e8804c82f0987c42729/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestIntegrationTests.java#L93) to show how it is done in practice. – barfuin Oct 24 '18 at 11:04
  • @barfuin - This looks like exactly what i need...except I'm using Boot v1.5 and that example uses features (TestPropertyValues) introduced in 2.0. Don't suppose anyone would have any other examples? – chrismacp May 06 '19 at 14:29
  • In Spring Boot 1.5.x you can use the `properties` attribute of `@SpringBootTest`: https://docs.spring.io/spring-boot/docs/1.5.21.BUILD-SNAPSHOT/api/org/springframework/boot/test/context/SpringBootTest.html#properties-- – Sam Brannen May 12 '19 at 16:15
9

You can also do this with the @DynamicPropertySource annotation in Spring Boot 5.2. This enables you to set the property value programmatically (dynamically).

See: https://github.com/spring-projects/spring-framework/issues/24540

Add this to your integration test class:

@DynamicPropertySource
static void dynamicProperties(DynamicPropertyRegistry registry) {
  registry.add("my.property", () -> {
       // some logic to get your property dynamically
   });
}
Raedwald
  • 46,613
  • 43
  • 151
  • 237
Amrit Baveja
  • 528
  • 7
  • 13
1

I did this thanks to Sam Brannen's answer

Here's the sample code:

@ContextConfiguration(classes = { MyConfiguration.class }, initializers = { MyInitializer.class })
public class MyContextConfiguration {
    public static class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            String userNameLower = System.getProperty("user.name").toLowerCase();
            Map<String, Object> dynamicProperties = Map.of("user.name.lower", userNameLower);
            MapPropertySource propertySource = new MapPropertySource("dynamic", dynamicProperties);
            applicationContext.getEnvironment().getPropertySources().addLast(propertySource);
        }
    }

    @Configuration
    @PropertySource("classpath:my-static.properties") // properties in this file can reference ${user.name.lower}
    public static class MyConfiguration {
        @Bean
        public MyBean myBean(@Value("${user.name.lower}") String userNameLower) {
            return new MyBean(userNameLower);
        }
    }
}
lance-java
  • 25,497
  • 4
  • 59
  • 101