-
Notifications
You must be signed in to change notification settings - Fork 38.8k
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,@PropertySourcedeclarations on test classes should be inherited by default but overridable. @PropertySourceis not an@Inheritedannotation, butAnnotationUtils.findAnnotationDeclaringClass()should take care of this.- Inheritance and overriding behavior of
@PropertySourcein integration tests must be consistent with the existing behavior in@Configurationclasses.- See code snippets from
ConfigurationClassPostProcessorandConfigurationClassParserbelow.
- 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
@Configurationclasses - Introduce @TestPropertySource support in the TestContext framework [SPR-12051] #16667 Introduce
@TestPropertySourcesupport in the TestContext framework ("is superseded by")
Referenced from: commits 3210041
4 votes, 8 watchers