Support resource patterns in @TestPropertySource locations
Inspired by the recently added support for resource patterns in
@PropertySource locations, this commit adds the same support for
resource locations in @TestPropertySource.
For example, assuming the `config` folder in the classpath contains
only 3 files matching the pattern `file?.properties`,
... the following:
@TestPropertySource("classpath:/config/file1.properties")
@TestPropertySource("classpath:/config/file2.properties")
@TestPropertySource("classpath:/config/file3.properties")
... or:
@TestPropertySource({
"classpath:/config/file1.properties",
"classpath:/config/file2.properties",
"classpath:/config/file3.properties"
})
... can now be replaced by:
@TestPropertySource("classpath*:/config/file?.properties")
See gh-21325
Closes gh-31055
This commit is contained in:
parent
3a38bb48b5
commit
1f544f113a
|
|
@ -37,9 +37,12 @@ Each path is interpreted as a Spring `Resource`. A plain path (for example,
|
|||
in which the test class is defined. A path starting with a slash is treated as an
|
||||
absolute classpath resource (for example: `"/org/example/test.xml"`). A path that
|
||||
references a URL (for example, a path prefixed with `classpath:`, `file:`, or `http:`) is
|
||||
loaded by using the specified resource protocol. Resource location wildcards (such as
|
||||
`{asterisk}{asterisk}/{asterisk}.properties`) are not permitted: Each location must
|
||||
evaluate to exactly one properties resource.
|
||||
loaded by using the specified resource protocol.
|
||||
|
||||
Property placeholders in paths (such as `${...}`) will be resolved against the `Environment`.
|
||||
|
||||
As of Spring Framework 6.1, resource location patterns are also supported — for
|
||||
example, `"classpath*:/config/*.properties"`.
|
||||
|
||||
The following example uses a test properties file:
|
||||
|
||||
|
|
|
|||
|
|
@ -110,9 +110,10 @@ public @interface TestPropertySource {
|
|||
|
||||
/**
|
||||
* The resource locations of properties files to be loaded into the
|
||||
* {@code Environment}'s set of {@code PropertySources}. Each location
|
||||
* will be added to the enclosing {@code Environment} as its own property
|
||||
* source, in the order declared.
|
||||
* {@code Environment}'s set of {@code PropertySources}.
|
||||
* <p>Each location will be added to the enclosing {@code Environment} as its
|
||||
* own property source, in the order declared (or in the order in which resource
|
||||
* locations are resolved when location wildcards are used).
|
||||
* <h4>Supported File Formats</h4>
|
||||
* <p>By default, both traditional and XML-based properties file formats are
|
||||
* supported — for example, {@code "classpath:/com/example/test.properties"}
|
||||
|
|
@ -130,11 +131,19 @@ public @interface TestPropertySource {
|
|||
* {@link org.springframework.util.ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
|
||||
* {@link org.springframework.util.ResourceUtils#FILE_URL_PREFIX file:},
|
||||
* {@code http:}, etc.) will be loaded using the specified resource protocol.
|
||||
* Resource location wildcards (e.g. <code>**/*.properties</code>)
|
||||
* are not permitted: each location must evaluate to exactly one properties
|
||||
* resource. Property placeholders in paths (i.e., <code>${...}</code>) will be
|
||||
* {@linkplain org.springframework.core.env.Environment#resolveRequiredPlaceholders(String) resolved}
|
||||
* against the {@code Environment}.
|
||||
* <p>Property placeholders in paths (i.e., <code>${...}</code>) will be
|
||||
* {@linkplain org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
|
||||
* resolved} against the {@code Environment}.
|
||||
* <p>As of Spring Framework 6.1, resource location patterns are also
|
||||
* supported — for example, {@code "classpath*:/config/*.properties"}.
|
||||
* <p><strong>WARNING</strong>: a pattern such as {@code "classpath*:/config/*.properties"}
|
||||
* may be effectively equivalent to an explicit enumeration of resource locations such as
|
||||
* <code>{"classpath:/config/mail.properties", classpath:/config/order.properties"}</code>;
|
||||
* however, the two declarations will result in different keys for the context
|
||||
* cache since the pattern cannot be eagerly resolved to concrete locations.
|
||||
* Consequently, to benefit from the context cache you must ensure that you
|
||||
* consistently use either patterns or explicit enumerations of resource
|
||||
* locations within your test suite.
|
||||
* <h4>Default Properties File Detection</h4>
|
||||
* <p>See the class-level Javadoc for a discussion on detection of defaults.
|
||||
* <h4>Precedence</h4>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ import org.springframework.core.io.support.DefaultPropertySourceFactory;
|
|||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.PropertySourceDescriptor;
|
||||
import org.springframework.core.io.support.PropertySourceFactory;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.context.TestContextAnnotationUtils;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
|
@ -202,6 +204,8 @@ public abstract class TestPropertySourceUtils {
|
|||
* <p>Property placeholders in resource locations (i.e., <code>${...}</code>)
|
||||
* will be {@linkplain Environment#resolveRequiredPlaceholders(String) resolved}
|
||||
* against the {@code Environment}.
|
||||
* <p>A {@link ResourcePatternResolver} will be used to resolve resource
|
||||
* location patterns into multiple resource locations.
|
||||
* <p>Each properties file will be converted to a
|
||||
* {@link org.springframework.core.io.support.ResourcePropertySource ResourcePropertySource}
|
||||
* that will be added to the {@link PropertySources} of the environment with
|
||||
|
|
@ -258,13 +262,15 @@ public abstract class TestPropertySourceUtils {
|
|||
* <p>Property placeholders in resource locations (i.e., <code>${...}</code>)
|
||||
* will be {@linkplain Environment#resolveRequiredPlaceholders(String) resolved}
|
||||
* against the {@code Environment}.
|
||||
* <p>A {@link ResourcePatternResolver} will be used to resolve resource
|
||||
* location patterns into multiple resource locations.
|
||||
* <p>Each {@link PropertySource} will be created via the configured
|
||||
* {@link PropertySourceDescriptor#propertySourceFactory() PropertySourceFactory}
|
||||
* (or the {@link DefaultPropertySourceFactory} if no factory is configured)
|
||||
* and added to the {@link PropertySources} of the environment with the highest
|
||||
* precedence.
|
||||
* @param environment the environment to update; never {@code null}
|
||||
* @param resourceLoader the {@code ResourceLoader} to use to load each resource;
|
||||
* @param resourceLoader the {@code ResourceLoader} to use to load resources;
|
||||
* never {@code null}
|
||||
* @param descriptors the property source descriptors to process; potentially
|
||||
* empty but never {@code null}
|
||||
|
|
@ -282,6 +288,8 @@ public abstract class TestPropertySourceUtils {
|
|||
Assert.notNull(environment, "'environment' must not be null");
|
||||
Assert.notNull(resourceLoader, "'resourceLoader' must not be null");
|
||||
Assert.notNull(descriptors, "'descriptors' must not be null");
|
||||
ResourcePatternResolver resourcePatternResolver =
|
||||
ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
try {
|
||||
for (PropertySourceDescriptor descriptor : descriptors) {
|
||||
|
|
@ -292,10 +300,11 @@ public abstract class TestPropertySourceUtils {
|
|||
|
||||
for (String location : descriptor.locations()) {
|
||||
String resolvedLocation = environment.resolveRequiredPlaceholders(location);
|
||||
Resource resource = resourceLoader.getResource(resolvedLocation);
|
||||
PropertySource<?> propertySource = factory.createPropertySource(descriptor.name(),
|
||||
new EncodedResource(resource, descriptor.encoding()));
|
||||
propertySources.addFirst(propertySource);
|
||||
for (Resource resource : resourcePatternResolver.getResources(resolvedLocation)) {
|
||||
PropertySource<?> propertySource = factory.createPropertySource(descriptor.name(),
|
||||
new EncodedResource(resource, descriptor.encoding()));
|
||||
propertySources.addFirst(propertySource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.env;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link TestPropertySource @TestPropertySource} support
|
||||
* for resource patterns for resource locations.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.1
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@TestPropertySource("classpath*:/org/springframework/test/context/env/pattern/file?.properties")
|
||||
class ResourcePatternExplicitPropertiesFileTests {
|
||||
|
||||
@Test
|
||||
void verifyPropertiesAreAvailableInEnvironment(@Autowired Environment env) {
|
||||
assertEnvironmentContainsProperties(env, "from.p1", "from.p2", "from.p3");
|
||||
}
|
||||
|
||||
|
||||
private static void assertEnvironmentContainsProperties(Environment env, String... names) {
|
||||
for (String name : names) {
|
||||
assertThat(env.containsProperty(name)).as("environment contains property '%s'", name).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
/* no user beans required for these tests */
|
||||
}
|
||||
|
||||
}
|
||||
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file1.properties
vendored
Normal file
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file1.properties
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
from.p1 = 1
|
||||
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file2.properties
vendored
Normal file
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file2.properties
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
from.p2 = 2
|
||||
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file3.properties
vendored
Normal file
1
spring-test/src/test/resources/org/springframework/test/context/env/pattern/file3.properties
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
from.p3 = 3
|
||||
Loading…
Reference in New Issue