Description
Paul Tomlin opened SPR-10232 and commented
Overview
When using the TestContext framework it would be nice to easily be able to specify some PropertySources
to be added to the Environment
, in much the same way as @ActiveProfiles
allows specifying the active profiles.
Ideally, something like below would result in a ResourcePropertySource
being registered with the environment of the test's ApplicationContext
prior to refresh:
@ContextConfiguration
@PropertySource("classpath:foo.properties")
public class MyTest {
// ...
}
Work-around
In Spring Framework 3.1, there is a workaround, but it's not nearly as tidy as the above proposal.
@ContextConfiguration(
locations = { ... },
loader = MyTest.CustomeContextLoader.class
)
public class MyTest {
public static class CustomContextLoader extends GenericXmlContextLoader {
@Override
protected void customizeContext(GenericApplicationContext context) {
// exception handling elided
context.getEnvironment()
.getPropertySources()
.addFirst(new ResourcePropertySource("classpath:foo.properties"));
}
}
}
There may be something in 3.2.x, probably as a result of #13650 and ApplicationContextInitializer
, but ContextLoaderUtils
doesn't seem to suggest so, and I'm not yet familiar enough to know.
Analysis
- As with
@ActiveProfiles
,@PropertySource
declarations on test classes should be inherited by default but overridable. @PropertySource
is not an@Inherited
annotation, butAnnotationUtils.findAnnotationDeclaringClass()
should take care of this.- Inheritance and overriding behavior of
@PropertySource
in integration tests must be consistent with the existing behavior in@Configuration
classes.- See code snippets from
ConfigurationClassPostProcessor
andConfigurationClassParser
below.
- See code snippets from
- As far as possible, the existing business logic in
ConfigurationClassParser.processPropertySource()
should be reused and not duplicated in the testing framework; in other words, consider extracting the existing logic into a static utility method or similar. - The context cache key (i.e.,
MergedContextConfiguration
) must take test property sources into account.
Relevant code from ConfigurationClassPostProcessor
// ...
// Handle any @PropertySource annotations
Stack<PropertySource<?>> parsedPropertySources = parser.getPropertySources();
if (!parsedPropertySources.isEmpty()) {
if (!(this.environment instanceof ConfigurableEnvironment)) {
logger.warn("Ignoring @PropertySource annotations. " +
"Reason: Environment must implement ConfigurableEnvironment");
}
else {
MutablePropertySources envPropertySources = ((ConfigurableEnvironment)this.environment).getPropertySources();
while (!parsedPropertySources.isEmpty()) {
envPropertySources.addLast(parsedPropertySources.pop());
}
}
}
// ...
Relevant code from ConfigurationClassParser
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
}
Affects: 3.1 GA
Issue Links:
- Support declarative PropertySource annotations in the TestContext framework [SPR-11377] #16004 Support declarative PropertySource annotations in the TestContext framework
- Allow the use of custom PropertySource annotations in @Configuration classes [SPR-8963] #13603 Allow the use of custom PropertySource annotations in
@Configuration
classes - Introduce @TestPropertySource support in the TestContext framework [SPR-12051] #16667 Introduce
@TestPropertySource
support in the TestContext framework ("is superseded by")
Referenced from: commits 3210041
4 votes, 8 watchers