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:
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?
@TestPropertySource documents that properties loaded from resource locations have lower precedence than inlined properties. I can't find anything that describes the precedence for @IntegrationTest. I also can't find anything that describes the relative precedence when @TestPropertySource and @IntegrationTest are used together.
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).
Can you please point me to the piece(s) of documentation that led to this understanding?
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Hard for me to say 100% what I was on about as this was posted months ago, but shouldn't properties provided by @IntegrationTest count as inlined properties in this case?
@beverage Thanks.
shouldn't properties provided by @IntegrationTest count as inlined properties in this case?
Possibly. On the face of if, your expectation seems reasonable but the problem is really that the order is undefined rather than it being implemented incorrectly. We can take a look at tightening things up in 1.4.
Please note that a related issue has been raised in SPR-14068: _Inlined properties in @TestPropertySource do not override values from properties files in Spring Boot_
FWIW I think by default we should follow the same rules as spring-test.
We are going to add the properties configured using properties on @SpringBootTest to the same property source as is used for properties configured using properties on @TestPropertySource. Inlined properties on @TestPropertySource will take precedence over those on @SpringBootTest and both will take precedence over properties from an external location configured using the locations attribute on @TestPropertySource.
Most helpful comment
FWIW I think by default we should follow the same rules as
spring-test.