Skip to content

Fully define precedence of properties when using SpringApplicationContextLoader #4828

@beverage

Description

@beverage

Hi,

Related to #2198 - while @TestPropertySource annotations are now providing environment variables from config files, they are not being applied in the correct order of precedence.

My understanding is that the external environment and config files are the lowest priority, followed by property source, test property source annotations, and lastly followed by test annotations (@IntegrationTest).

Here is a test showing the current behaviors:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { SpringBootBugTest.Config.class, SpringBootBugTest.MoreConfig.class })  // Config is the same as tests in #2198
@WebAppConfiguration
@TestPropertySource(locations  = "classpath:/test.properties",
//
// From config file:  "value1=123", "value2=123" 
    properties = {                  "value2=456",               "value4=456", "value5=456" })
@IntegrationTest({    "value1=789",               "value3=789",               "value5=789" })
//                    ------------  ------------  ------------  ------------  ------------
// Expected results:   value1=789    value2=456    value3=789    value4=456    value5=789
public class SpringBootBugTest {

    @Autowired 
    private SpringBootBugTest.MoreConfig moreConfig;

    @Test
    public void value1fromConfigIsOverridenByIntegrationTest() {
        assertThat(moreConfig.getValue1(), equalTo("789"));
    }

    @Test
    public void value2fromConfigIsOverridenByTestPropertySource() {
        assertThat(moreConfig.getValue2(), equalTo("456"));
    }

    @Test
    public void value3isFromIntegrationTest() {
        assertThat(moreConfig.getValue3(), equalTo("789"));
    }

    @Test
    public void value4isFromTestPropertySource() {
        assertThat(moreConfig.getValue4(), equalTo("456"));
    }

    @Test
    public void value5fromIntegrationTestIsOverridingTestPropertySource() {
        assertThat(moreConfig.getValue5(), equalTo("789"));
    }

    public static class MoreConfig {

        @Value("${value1}")
        private String value1;

        @Value("${value2}")
        private String value2;

        @Value("${value3}")
        private String value3;

        @Value("${value4}")
        private String value4;

        @Value("${value5}")
        private String value5;

        public String getValue1() {
            return value1;
        }

        public String getValue2() {
            return value2;
        }

        public String getValue3() {
            return value3;
        }

        public String getValue4() {
            return value4;
        }

        public String getValue5() {
            return value5;
        }
    }
}

Results:

  1. 123 from config file is returned - expected 789 from @IntegrationTEST
  2. 123 from config file is returned - expected 456 from @TestPropertySource
  3. Passes - 789 from @IntegrationTEST is returned
  4. Passes - 456 from @TestPropertySource is returned
  5. Passes - 789 from @IntegrationTEST is returned

It seems that PropertySourceLocationsInitializer.initialize that was added in the earlier commit is being called after loadContext. Is there a reason we are not loading the config file environment variables there, in loadContext, before checking the inlined properties?

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions