Skip to content

Commit 69b0829

Browse files
committed
Align precedence of @SpringBootTest properties with @TestPropertySource
This commit updates the precedence of properties configured using @SpringBootTest to align with @TestPropertySource. Properties configured using properties on @SpringBootTest are now added to the same property source as those configured using properties on @TestPropertySource so the precedence described in the javadoc of @TestPropertySource now applies in full. Additionally, if both @TestPropertySource properties and @SpringBootTest properties configure the same property, the value from @TestPropertySource will win. Closes gh-4828
1 parent 5f5db17 commit 69b0829

File tree

5 files changed

+137
-114
lines changed

5 files changed

+137
-114
lines changed

spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
import java.util.ArrayList;
2020
import java.util.Arrays;
2121
import java.util.Collections;
22-
import java.util.LinkedHashMap;
2322
import java.util.LinkedHashSet;
2423
import java.util.List;
25-
import java.util.Map;
2624
import java.util.Set;
2725

2826
import org.springframework.beans.BeanUtils;
@@ -36,7 +34,6 @@
3634
import org.springframework.core.SpringVersion;
3735
import org.springframework.core.annotation.AnnotatedElementUtils;
3836
import org.springframework.core.env.ConfigurableEnvironment;
39-
import org.springframework.core.env.MapPropertySource;
4037
import org.springframework.core.env.StandardEnvironment;
4138
import org.springframework.test.context.ContextConfigurationAttributes;
4239
import org.springframework.test.context.ContextCustomizer;
@@ -90,8 +87,6 @@ public ApplicationContext loadContext(MergedContextConfiguration config)
9087
if (!ObjectUtils.isEmpty(config.getActiveProfiles())) {
9188
setActiveProfiles(environment, config.getActiveProfiles());
9289
}
93-
Map<String, Object> properties = getEnvironmentProperties(config);
94-
addProperties(environment, properties);
9590
application.setEnvironment(environment);
9691
List<ApplicationContextInitializer<?>> initializers = getInitializers(config,
9792
application);
@@ -135,29 +130,19 @@ private void setActiveProfiles(ConfigurableEnvironment environment,
135130
+ StringUtils.arrayToCommaDelimitedString(profiles));
136131
}
137132

138-
protected Map<String, Object> getEnvironmentProperties(
139-
MergedContextConfiguration config) {
140-
Map<String, Object> properties = new LinkedHashMap<String, Object>();
133+
protected String[] getInlinedProperties(MergedContextConfiguration config) {
134+
ArrayList<String> properties = new ArrayList<String>();
141135
// JMX bean names will clash if the same bean is used in multiple contexts
142136
disableJmx(properties);
143-
properties.putAll(TestPropertySourceUtils
144-
.convertInlinedPropertiesToMap(config.getPropertySourceProperties()));
137+
properties.addAll(Arrays.asList(config.getPropertySourceProperties()));
145138
if (!isEmbeddedWebEnvironment(config)) {
146-
properties.put("server.port", "-1");
139+
properties.add("server.port=-1");
147140
}
148-
return properties;
141+
return properties.toArray(new String[properties.size()]);
149142
}
150143

151-
private void disableJmx(Map<String, Object> properties) {
152-
properties.put("spring.jmx.enabled", "false");
153-
}
154-
155-
private void addProperties(ConfigurableEnvironment environment,
156-
Map<String, Object> properties) {
157-
// @IntegrationTest properties go before external configuration and after system
158-
environment.getPropertySources().addAfter(
159-
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
160-
new MapPropertySource("integrationTest", properties));
144+
private void disableJmx(List<String> properties) {
145+
properties.add("spring.jmx.enabled=false");
161146
}
162147

163148
private List<ApplicationContextInitializer<?>> getInitializers(
@@ -166,8 +151,8 @@ private List<ApplicationContextInitializer<?>> getInitializers(
166151
for (ContextCustomizer contextCustomizer : config.getContextCustomizers()) {
167152
initializers.add(new ContextCustomizerAdapter(contextCustomizer, config));
168153
}
169-
initializers.add(new PropertySourceLocationsInitializer(
170-
config.getPropertySourceLocations()));
154+
initializers.add(new TestPropertySourcesInitializer(
155+
config.getPropertySourceLocations(), getInlinedProperties(config)));
171156
initializers.addAll(application.getInitializers());
172157
for (Class<? extends ApplicationContextInitializer<?>> initializerClass : config
173158
.getContextInitializerClasses()) {
@@ -258,21 +243,27 @@ private void addMockServletContext(
258243
}
259244

260245
/**
261-
* {@link ApplicationContextInitializer} to setup test property source locations.
246+
* {@link ApplicationContextInitializer} to set up test property sources.
262247
*/
263-
private static class PropertySourceLocationsInitializer
248+
private static class TestPropertySourcesInitializer
264249
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
265250

266251
private final String[] propertySourceLocations;
267252

268-
PropertySourceLocationsInitializer(String[] propertySourceLocations) {
253+
private final String[] inlinedProperties;
254+
255+
TestPropertySourcesInitializer(String[] propertySourceLocations,
256+
String[] inlinedProperties) {
269257
this.propertySourceLocations = propertySourceLocations;
258+
this.inlinedProperties = inlinedProperties;
270259
}
271260

272261
@Override
273262
public void initialize(ConfigurableApplicationContext applicationContext) {
274263
TestPropertySourceUtils.addPropertiesFilesToEnvironment(applicationContext,
275264
this.propertySourceLocations);
265+
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,
266+
this.inlinedProperties);
276267
}
277268

278269
}

spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ protected void processPropertySourceProperties(
206206
Class<?> testClass = mergedConfig.getTestClass();
207207
String[] properties = getProperties(testClass);
208208
if (!ObjectUtils.isEmpty(properties)) {
209-
propertySourceProperties.addAll(Arrays.asList(properties));
209+
// Added first so that inlined properties from @TestPropertySource take
210+
// precedence
211+
propertySourceProperties.addAll(0, Arrays.asList(properties));
210212
}
211213
if (getWebEnvironment(testClass) == WebEnvironment.RANDOM_PORT) {
212214
propertySourceProperties.add("server.port=0");

spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestPropertyLocationTests.java

Lines changed: 0 additions & 85 deletions
This file was deleted.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.context;
18+
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.beans.factory.annotation.Value;
24+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
28+
import org.springframework.test.annotation.DirtiesContext;
29+
import org.springframework.test.context.TestPropertySource;
30+
import org.springframework.test.context.junit4.SpringRunner;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Tests for using {@link SpringBootTest} with {@link TestPropertySource}.
36+
*
37+
* @author Phillip Webb
38+
* @author Andy Wilkinson
39+
*/
40+
@RunWith(SpringRunner.class)
41+
@DirtiesContext
42+
@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = {
43+
"boot-test-inlined=foo", "b=boot-test-inlined", "c=boot-test-inlined" })
44+
@TestPropertySource(properties = { "property-source-inlined=bar",
45+
"a=property-source-inlined",
46+
"c=property-source-inlined" }, locations = "classpath:/test-property-source-annotation.properties")
47+
public class SpringBootTestWithTestPropertySourceTests {
48+
49+
@Autowired
50+
private Config config;
51+
52+
@Test
53+
public void propertyFromSpringBootTestProperties() {
54+
assertThat(this.config.bootTestInlined).isEqualTo("foo");
55+
}
56+
57+
@Test
58+
public void propertyFromTestPropertySourceProperties() {
59+
assertThat(this.config.propertySourceInlined).isEqualTo("bar");
60+
}
61+
62+
@Test
63+
public void propertyFromTestPropertySourceLocations() {
64+
assertThat(this.config.propertySourceLocation).isEqualTo("baz");
65+
}
66+
67+
@Test
68+
public void propertyFromPropertySourcePropertiesOverridesPropertyFromPropertySourceLocations() {
69+
assertThat(this.config.propertySourceInlinedOverridesPropertySourceLocation)
70+
.isEqualTo("property-source-inlined");
71+
}
72+
73+
@Test
74+
public void propertyFromBootTestPropertiesOverridesPropertyFromPropertySourceLocations() {
75+
assertThat(this.config.bootTestInlinedOverridesPropertySourceLocation)
76+
.isEqualTo("boot-test-inlined");
77+
}
78+
79+
@Test
80+
public void propertyFromPropertySourcePropertiesOverridesPropertyFromBootTestProperties() {
81+
assertThat(this.config.propertySourceInlinedOverridesBootTestInlined)
82+
.isEqualTo("property-source-inlined");
83+
}
84+
85+
@Configuration
86+
static class Config {
87+
88+
@Value("${boot-test-inlined}")
89+
private String bootTestInlined;
90+
91+
@Value("${property-source-inlined}")
92+
private String propertySourceInlined;
93+
94+
@Value("${property-source-location}")
95+
private String propertySourceLocation;
96+
97+
@Value("${a}")
98+
private String propertySourceInlinedOverridesPropertySourceLocation;
99+
100+
@Value("${b}")
101+
private String bootTestInlinedOverridesPropertySourceLocation;
102+
103+
@Value("${c}")
104+
private String propertySourceInlinedOverridesBootTestInlined;
105+
106+
@Bean
107+
public static PropertySourcesPlaceholderConfigurer propertyPlaceholder() {
108+
return new PropertySourcesPlaceholderConfigurer();
109+
}
110+
111+
}
112+
113+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
annotation-referenced=fromfile
1+
property-source-location=baz
2+
a=property-source-location
3+
b=property-source-location

0 commit comments

Comments
 (0)