Browse Source

Merge branch 'sbrannen/issues/gh-23320-repeatable-TestPropertySource'

pull/23382/head
Sam Brannen 7 years ago
parent
commit
690694df33
  1. 6
      spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java
  2. 50
      spring-test/src/main/java/org/springframework/test/context/TestPropertySources.java
  3. 82
      spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java
  4. 179
      spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java
  5. 44
      spring-test/src/test/java/org/springframework/test/context/env/TestPropertySourceTestSuite.java
  6. 31
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractClassWithTestProperty.java
  7. 54
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractRepeatableTestPropertySourceTests.java
  8. 42
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.java
  9. 45
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/ExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
  10. 40
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndInheritedInlinedPropertyTests.java
  11. 41
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndMetaInlinedPropertyTests.java
  12. 52
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.java
  13. 43
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedInlinedPropertyTests.java
  14. 40
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesMetaInlinedPropertyTests.java
  15. 62
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalPropertiesFileAndMetaPropertiesFileTests.java
  16. 37
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/MetaInlinedTestProperty.java
  17. 43
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/RepeatedTestPropertySourceTests.java
  18. 41
      spring-test/src/test/java/org/springframework/test/context/env/repeatable/ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests.java
  19. 112
      spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java
  20. 1
      spring-test/src/test/resources/log4j2-test.xml
  21. 1
      spring-test/src/test/resources/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.properties
  22. 3
      spring-test/src/test/resources/org/springframework/test/context/env/repeatable/first.properties
  23. 1
      spring-test/src/test/resources/org/springframework/test/context/env/repeatable/local.properties
  24. 1
      spring-test/src/test/resources/org/springframework/test/context/env/repeatable/meta.properties
  25. 2
      spring-test/src/test/resources/org/springframework/test/context/env/repeatable/second.properties
  26. 19
      src/docs/asciidoc/testing.adoc

6
spring-test/src/main/java/org/springframework/test/context/TestPropertySource.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2019 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.
@ -19,6 +19,7 @@ package org.springframework.test.context; @@ -19,6 +19,7 @@ package org.springframework.test.context;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@ -67,6 +68,8 @@ import org.springframework.core.annotation.AliasFor; @@ -67,6 +68,8 @@ import org.springframework.core.annotation.AliasFor;
* <ul>
* <li>Typically, {@code @TestPropertySource} will be used in conjunction with
* {@link ContextConfiguration @ContextConfiguration}.</li>
* <li>As of Spring Framework 5.2, {@code @TestPropertySource} can be used as a
* <em>{@linkplain Repeatable repeatable}</em> annotation.</li>
* <li>This annotation may be used as a <em>meta-annotation</em> to create
* custom <em>composed annotations</em>; however, caution should be taken if
* this annotation and {@code @ContextConfiguration} are combined on a composed
@ -86,6 +89,7 @@ import org.springframework.core.annotation.AliasFor; @@ -86,6 +89,7 @@ import org.springframework.core.annotation.AliasFor;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Repeatable(TestPropertySources.class)
public @interface TestPropertySource {
/**

50
spring-test/src/main/java/org/springframework/test/context/TestPropertySources.java

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
/*
* Copyright 2002-2019 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;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* {@code @TestPropertySources} is a container for one or more
* {@link TestPropertySource @TestPropertySource} declarations.
*
* <p>Note, however, that use of the {@code @TestPropertySources} container is
* completely optional since {@code @TestPropertySource} is a
* {@linkplain java.lang.annotation.Repeatable repeatable} annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TestPropertySources {
/**
* An array of one or more {@link TestPropertySource @TestPropertySource}
* declarations.
*/
TestPropertySource[] value();
}

82
spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceAttributes.java

@ -16,25 +16,19 @@ @@ -16,25 +16,19 @@
package org.springframework.test.context.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.List;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable;
import org.springframework.test.context.TestPropertySource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
/**
* {@code TestPropertySourceAttributes} encapsulates the attributes declared
* via {@link TestPropertySource @TestPropertySource}.
* {@code TestPropertySourceAttributes} encapsulates attributes declared
* via {@link TestPropertySource @TestPropertySource} annotations.
*
* <p>In addition to encapsulating declared attributes,
* {@code TestPropertySourceAttributes} also enforces configuration rules
* and detects default properties files.
* {@code TestPropertySourceAttributes} also enforces configuration rules.
*
* @author Sam Brannen
* @since 4.1
@ -43,8 +37,6 @@ import org.springframework.util.ResourceUtils; @@ -43,8 +37,6 @@ import org.springframework.util.ResourceUtils;
*/
class TestPropertySourceAttributes {
private static final Log logger = LogFactory.getLog(TestPropertySourceAttributes.class);
private final Class<?> declaringClass;
private final String[] locations;
@ -57,27 +49,29 @@ class TestPropertySourceAttributes { @@ -57,27 +49,29 @@ class TestPropertySourceAttributes {
/**
* Create a new {@code TestPropertySourceAttributes} instance for the
* supplied {@link TestPropertySource @TestPropertySource} annotation and
* the {@linkplain Class test class} that declared it, enforcing
* configuration rules and detecting a default properties file if
* necessary.
* Create a new {@code TestPropertySourceAttributes} instance for the supplied
* values and enforce configuration rules.
* @param declaringClass the class that declared {@code @TestPropertySource}
* @param testPropertySource the annotation from which to retrieve the attributes
* @since 4.2
* @param locations the merged {@link TestPropertySource#locations()}
* @param inheritLocations the {@link TestPropertySource#inheritLocations()} flag
* @param properties the merged {@link TestPropertySource#properties()}
* @param inheritProperties the {@link TestPropertySource#inheritProperties()} flag
* @since 5.2
*/
TestPropertySourceAttributes(Class<?> declaringClass, TestPropertySource testPropertySource) {
this(declaringClass, testPropertySource.locations(), testPropertySource.inheritLocations(),
testPropertySource.properties(), testPropertySource.inheritProperties());
TestPropertySourceAttributes(Class<?> declaringClass, List<String> locations, boolean inheritLocations,
List<String> properties, boolean inheritProperties) {
this(declaringClass, locations.toArray(new String[0]), inheritLocations, properties.toArray(new String[0]),
inheritProperties);
}
private TestPropertySourceAttributes(Class<?> declaringClass, String[] locations, boolean inheritLocations,
String[] properties, boolean inheritProperties) {
Assert.notNull(declaringClass, "declaringClass must not be null");
if (ObjectUtils.isEmpty(locations) && ObjectUtils.isEmpty(properties)) {
locations = new String[] { detectDefaultPropertiesFile(declaringClass) };
}
Assert.notNull(declaringClass, "'declaringClass' must not be null");
Assert.isTrue(!ObjectUtils.isEmpty(locations) || !ObjectUtils.isEmpty(properties),
"Either 'locations' or 'properties' are required");
this.declaringClass = declaringClass;
this.locations = locations;
this.inheritLocations = inheritLocations;
@ -97,7 +91,8 @@ class TestPropertySourceAttributes { @@ -97,7 +91,8 @@ class TestPropertySourceAttributes {
/**
* Get the resource locations that were declared via {@code @TestPropertySource}.
* <p>Note: The returned value may represent a <em>detected default</em>
* that does not match the original value declared via {@code @TestPropertySource}.
* or merged locations that do not match the original value declared via a
* single {@code @TestPropertySource} annotation.
* @return the resource locations; potentially <em>empty</em>
* @see TestPropertySource#value
* @see TestPropertySource#locations
@ -117,10 +112,12 @@ class TestPropertySourceAttributes { @@ -117,10 +112,12 @@ class TestPropertySourceAttributes {
/**
* Get the inlined properties that were declared via {@code @TestPropertySource}.
* @return the inlined properties; potentially {@code null} or <em>empty</em>
* <p>Note: The returned value may represent merged properties that do not
* match the original value declared via a single {@code @TestPropertySource}
* annotation.
* @return the inlined properties; potentially <em>empty</em>
* @see TestPropertySource#properties
*/
@Nullable
String[] getProperties() {
return this.properties;
}
@ -149,31 +146,4 @@ class TestPropertySourceAttributes { @@ -149,31 +146,4 @@ class TestPropertySourceAttributes {
.toString();
}
/**
* Detect a default properties file for the supplied class, as specified
* in the class-level Javadoc for {@link TestPropertySource}.
*/
private static String detectDefaultPropertiesFile(Class<?> testClass) {
String resourcePath = ClassUtils.convertClassNameToResourcePath(testClass.getName()) + ".properties";
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
if (classPathResource.exists()) {
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
if (logger.isInfoEnabled()) {
logger.info(String.format("Detected default properties file \"%s\" for test class [%s]",
prefixedResourcePath, testClass.getName()));
}
return prefixedResourcePath;
}
else {
String msg = String.format("Could not detect default properties file for test [%s]: " +
"%s does not exist. Either declare the 'locations' or 'properties' attributes " +
"of @TestPropertySource or make the default properties file available.", testClass.getName(),
classPathResource);
logger.error(msg);
throw new IllegalStateException(msg);
}
}
}

179
spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@ -20,32 +20,39 @@ import java.io.IOException; @@ -20,32 +20,39 @@ import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.util.TestContextResourceUtils;
import org.springframework.test.util.MetaAnnotationUtils.AnnotationDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDescriptor;
/**
* Utility methods for working with {@link TestPropertySource @TestPropertySource}
* and adding test {@link PropertySource PropertySources} to the {@code Environment}.
@ -53,6 +60,7 @@ import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDe @@ -53,6 +60,7 @@ import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDe
* <p>Primarily intended for use within the framework.
*
* @author Sam Brannen
* @author Anatoliy Korovin
* @since 4.1
* @see TestPropertySource
*/
@ -67,47 +75,152 @@ public abstract class TestPropertySourceUtils { @@ -67,47 +75,152 @@ public abstract class TestPropertySourceUtils {
private static final Log logger = LogFactory.getLog(TestPropertySourceUtils.class);
/**
* Compares {@link MergedAnnotation} instances (presumably within the same
* aggregate index) by their meta-distance, in reverse order.
* <p>Using this {@link Comparator} to sort according to reverse meta-distance
* ensures that directly present annotations take precedence over meta-present
* annotations (within a given aggregate index). In other words, this follows
* the last-one-wins principle of overriding properties.
* @see MergedAnnotation#getAggregateIndex()
* @see MergedAnnotation#getDistance()
*/
private static final Comparator<? super MergedAnnotation<?>> reversedMetaDistanceComparator =
Comparator.<MergedAnnotation<?>> comparingInt(MergedAnnotation::getDistance).reversed();
static MergedTestPropertySources buildMergedTestPropertySources(Class<?> testClass) {
Class<TestPropertySource> annotationType = TestPropertySource.class;
AnnotationDescriptor<TestPropertySource> descriptor = findAnnotationDescriptor(testClass, annotationType);
if (descriptor == null) {
return new MergedTestPropertySources();
}
MergedAnnotations mergedAnnotations = MergedAnnotations.from(testClass, SearchStrategy.EXHAUSTIVE);
return (mergedAnnotations.isPresent(TestPropertySource.class) ? mergeTestPropertySources(mergedAnnotations) :
new MergedTestPropertySources());
}
List<TestPropertySourceAttributes> attributesList = resolveTestPropertySourceAttributes(testClass);
String[] locations = mergeLocations(attributesList);
String[] properties = mergeProperties(attributesList);
return new MergedTestPropertySources(locations, properties);
private static MergedTestPropertySources mergeTestPropertySources(MergedAnnotations mergedAnnotations) {
List<TestPropertySourceAttributes> attributesList = resolveTestPropertySourceAttributes(mergedAnnotations);
return new MergedTestPropertySources(mergeLocations(attributesList), mergeProperties(attributesList));
}
private static List<TestPropertySourceAttributes> resolveTestPropertySourceAttributes(Class<?> testClass) {
Assert.notNull(testClass, "Class must not be null");
List<TestPropertySourceAttributes> attributesList = new ArrayList<>();
Class<TestPropertySource> annotationType = TestPropertySource.class;
private static List<TestPropertySourceAttributes> resolveTestPropertySourceAttributes(
MergedAnnotations mergedAnnotations) {
AnnotationDescriptor<TestPropertySource> descriptor = findAnnotationDescriptor(testClass, annotationType);
Assert.notNull(descriptor, String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]",
annotationType.getName(), testClass.getName()));
// Group by aggregate index to ensure proper separation of inherited and local annotations.
Map<Integer, List<MergedAnnotation<TestPropertySource>>> aggregateIndexMap = mergedAnnotations
.stream(TestPropertySource.class)
.collect(Collectors.groupingBy(MergedAnnotation::getAggregateIndex, TreeMap::new,
Collectors.mapping(x -> x, Collectors.toList())));
while (descriptor != null) {
TestPropertySource testPropertySource = descriptor.synthesizeAnnotation();
Class<?> rootDeclaringClass = descriptor.getRootDeclaringClass();
if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @TestPropertySource [%s] for declaring class [%s].",
testPropertySource, rootDeclaringClass.getName()));
// Stream the lists of annotations per aggregate index, merge each list into a
// single TestPropertySourceAttributes instance, and collect the results.
return aggregateIndexMap.values().stream()
.map(TestPropertySourceUtils::createTestPropertySourceAttributes)
.collect(Collectors.toList());
}
/**
* Create a merged {@link TestPropertySourceAttributes} instance from all
* annotations in the supplied list for a given aggregate index as if there
* were only one such annotation.
* <p>Within the supplied list, sort according to reversed meta-distance of
* the annotations from the declaring class. This ensures that directly present
* annotations take precedence over meta-present annotations within the current
* aggregate index.
* <p>If a given {@link TestPropertySource @TestPropertySource} does not
* declare properties or locations, an attempt will be made to detect a default
* properties file.
*/
private static TestPropertySourceAttributes createTestPropertySourceAttributes(
List<MergedAnnotation<TestPropertySource>> list) {
list.sort(reversedMetaDistanceComparator);
List<String> locations = new ArrayList<>();
List<String> properties = new ArrayList<>();
Class<?> declaringClass = null;
Boolean inheritLocations = null;
Boolean inheritProperties = null;
// Merge all @TestPropertySource annotations within the current
// aggregate index into a single TestPropertySourceAttributes instance,
// simultaneously ensuring that all such annotations have the same
// declaringClass, inheritLocations, and inheritProperties values.
for (MergedAnnotation<TestPropertySource> mergedAnnotation : list) {
Class<?> currentDeclaringClass = (Class<?>) mergedAnnotation.getSource();
if (declaringClass != null && !declaringClass.equals(currentDeclaringClass)) {
throw new IllegalStateException("Detected @TestPropertySource declarations within an aggregate index " +
"with different declaring classes: " + declaringClass.getName() + " and " +
currentDeclaringClass.getName());
}
TestPropertySourceAttributes attributes =
new TestPropertySourceAttributes(rootDeclaringClass, testPropertySource);
declaringClass = currentDeclaringClass;
TestPropertySource testPropertySource = mergedAnnotation.synthesize();
if (logger.isTraceEnabled()) {
logger.trace("Resolved TestPropertySource attributes: " + attributes);
logger.trace(String.format("Retrieved %s for declaring class [%s].", testPropertySource,
declaringClass.getName()));
}
Boolean currentInheritLocations = testPropertySource.inheritLocations();
assertConsistentValues(testPropertySource, declaringClass, "inheritLocations", inheritLocations,
currentInheritLocations);
inheritLocations = currentInheritLocations;
Boolean currentInheritProperties = testPropertySource.inheritProperties();
assertConsistentValues(testPropertySource, declaringClass, "inheritProperties", inheritProperties,
currentInheritProperties);
inheritProperties = currentInheritProperties;
String[] currentLocations = testPropertySource.locations();
String[] currentProperties = testPropertySource.properties();
if (ObjectUtils.isEmpty(currentLocations) && ObjectUtils.isEmpty(currentProperties)) {
locations.add(detectDefaultPropertiesFile(declaringClass));
}
else {
Collections.addAll(locations, currentLocations);
Collections.addAll(properties, currentProperties);
}
attributesList.add(attributes);
descriptor = findAnnotationDescriptor(rootDeclaringClass.getSuperclass(), annotationType);
}
return attributesList;
TestPropertySourceAttributes attributes = new TestPropertySourceAttributes(declaringClass, locations,
inheritLocations, properties, inheritProperties);
if (logger.isTraceEnabled()) {
logger.trace(String.format("Resolved @TestPropertySource attributes %s for declaring class [%s].",
attributes, declaringClass.getName()));
}
return attributes;
}
private static void assertConsistentValues(TestPropertySource testPropertySource, Class<?> declaringClass,
String attributeName, Object trackedValue, Object currentValue) {
Assert.isTrue((trackedValue == null || trackedValue.equals(currentValue)),
() -> String.format("%s on class [%s] must declare the same value for '%s' " +
"as other directly present or meta-present @TestPropertySource annotations on [%2$s].",
testPropertySource, declaringClass.getName(), attributeName));
}
/**
* Detect a default properties file for the supplied class, as specified
* in the class-level Javadoc for {@link TestPropertySource}.
*/
private static String detectDefaultPropertiesFile(Class<?> testClass) {
String resourcePath = ClassUtils.convertClassNameToResourcePath(testClass.getName()) + ".properties";
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
if (classPathResource.exists()) {
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
if (logger.isInfoEnabled()) {
logger.info(String.format("Detected default properties file \"%s\" for test class [%s]",
prefixedResourcePath, testClass.getName()));
}
return prefixedResourcePath;
}
else {
String msg = String.format("Could not detect default properties file for test class [%s]: " +
"%s does not exist. Either declare the 'locations' or 'properties' attributes " +
"of @TestPropertySource or make the default properties file available.", testClass.getName(),
classPathResource);
logger.error(msg);
throw new IllegalStateException(msg);
}
}
private static String[] mergeLocations(List<TestPropertySourceAttributes> attributesList) {

44
spring-test/src/test/java/org/springframework/test/context/env/TestPropertySourceTestSuite.java vendored

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
/*
* Copyright 2002-2019 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.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.UseTechnicalNames;
import org.junit.runner.RunWith;
import org.springframework.test.context.TestPropertySource;
/**
* Test suite for tests that involve {@link TestPropertySource @TestPropertySource}.
*
* <p>Note that tests included in this suite will be executed at least twice if
* run from an automated build process, test runner, etc. that is not configured
* to exclude tests based on a {@code "*TestSuite.class"} pattern match.
*
* @author Sam Brannen
* @since 5.2
*/
@RunWith(JUnitPlatform.class)
@IncludeEngines("junit-vintage")
@SelectPackages("org.springframework.test.context.env")
@IncludeClassNamePatterns(".*Tests$")
@UseTechnicalNames
public class TestPropertySourceTestSuite {
}

31
spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractClassWithTestProperty.java vendored

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.springframework.test.context.TestPropertySource;
/**
* Abstract base class which declares an inlined property via
* {@link TestPropertySource @TestPropertySource}.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "key1 = parent")
abstract class AbstractClassWithTestProperty extends AbstractRepeatableTestPropertySourceTests {
}

54
spring-test/src/test/java/org/springframework/test/context/env/repeatable/AbstractRepeatableTestPropertySourceTests.java vendored

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Abstract base class for integration tests involving
* {@link TestPropertySource @TestPropertySource} as a repeatable annotation.
*
* @author Sam Brannen
* @since 5.2
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
abstract class AbstractRepeatableTestPropertySourceTests {
@Autowired
Environment env;
protected void assertEnvironmentValue(String key, String expected) {
assertThat(env.getProperty(key)).as("Value of key [" + key + "].").isEqualTo(expected);
}
@Configuration
static class Config {
}
}

42
spring-test/src/test/java/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.java vendored

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource
@TestPropertySource("local.properties")
public class DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests
extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("default.value", "default file");
assertEnvironmentValue("key1", "local file");
}
}

45
spring-test/src/test/java/org/springframework/test/context/env/repeatable/ExplicitPropertiesFilesRepeatedTestPropertySourceTests.java vendored

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* <p>Same as {@link ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests},
* but with the order of the properties files reversed.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource("first.properties")
@TestPropertySource("second.properties")
public class ExplicitPropertiesFilesRepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("alpha", "omega");
assertEnvironmentValue("first", "1111");
assertEnvironmentValue("second", "2222");
}
}

40
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndInheritedInlinedPropertyTests.java vendored

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "key2 = local")
public class LocalInlinedPropertyAndInheritedInlinedPropertyTests extends AbstractClassWithTestProperty {
@Test
public void test() {
assertEnvironmentValue("key1", "parent");
assertEnvironmentValue("key2", "local");
}
}

41
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyAndMetaInlinedPropertyTests.java vendored

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "key1 = local")
@MetaInlinedTestProperty
public class LocalInlinedPropertyAndMetaInlinedPropertyTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("key1", "local");
assertEnvironmentValue("meta", "inlined");
}
}

52
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.java vendored

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
/*
* Copyright 2002-2019 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.repeatable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.env.repeatable.LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests.Key1InlinedTestProperty;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "key1 = local")
@Key1InlinedTestProperty
public class LocalInlinedPropertyOverridesInheritedAndMetaInlinedPropertiesTests extends AbstractClassWithTestProperty {
@Test
public void test() {
assertEnvironmentValue("key1", "local");
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestPropertySource(properties = "key1 = meta")
@interface Key1InlinedTestProperty {
}
}

43
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesInheritedInlinedPropertyTests.java vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "key1 = local value")
@TestPropertySource(properties = "second = local override")
public class LocalInlinedPropertyOverridesInheritedInlinedPropertyTests extends RepeatedTestPropertySourceTests {
@Test
@Override
public void test() {
assertEnvironmentValue("key1", "local value");
assertEnvironmentValue("second", "local override");
assertEnvironmentValue("first", "repeated override");
}
}

40
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalInlinedPropertyOverridesMetaInlinedPropertyTests.java vendored

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "meta = local override")
@MetaInlinedTestProperty
public class LocalInlinedPropertyOverridesMetaInlinedPropertyTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("meta", "local override");
}
}

62
spring-test/src/test/java/org/springframework/test/context/env/repeatable/LocalPropertiesFileAndMetaPropertiesFileTests.java vendored

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
/*
* Copyright 2002-2019 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.repeatable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.env.repeatable.LocalPropertiesFileAndMetaPropertiesFileTests.MetaFileTestProperty;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* <p>Verify a property value is defined both in the properties file which is declared
* via {@link MetaFileTestProperty @MetaFileTestProperty} and in the properties file
* which is declared locally via {@code @TestPropertySource}.
*
* @author Anatoliy Korovin
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource("local.properties")
@MetaFileTestProperty
public class LocalPropertiesFileAndMetaPropertiesFileTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("key1", "local file");
assertEnvironmentValue("key2", "meta file");
}
/**
* Composed annotation that declares a properties file via
* {@link TestPropertySource @TestPropertySource}.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestPropertySource("meta.properties")
@interface MetaFileTestProperty {
}
}

37
spring-test/src/test/java/org/springframework/test/context/env/repeatable/MetaInlinedTestProperty.java vendored

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
/*
* Copyright 2002-2019 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.repeatable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.test.context.TestPropertySource;
/**
* Composed annotation that declares a {@code meta} inlined property via
* {@link TestPropertySource @TestPropertySource}.
*
* @author Anatoliy Korovin
* @since 5.2
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestPropertySource(properties = "meta = inlined")
@interface MetaInlinedTestProperty {
}

43
spring-test/src/test/java/org/springframework/test/context/env/repeatable/RepeatedTestPropertySourceTests.java vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource} as a
* repeatable annotation.
*
* <p>Tests multiple local {@link TestPropertySource} declarations.
*
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource(properties = "first = repeated")
@TestPropertySource(properties = "second = repeated")
@TestPropertySource(properties = "first = repeated override")
public class RepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("first", "repeated override");
assertEnvironmentValue("second", "repeated");
}
}

41
spring-test/src/test/java/org/springframework/test/context/env/repeatable/ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests.java vendored

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* Copyright 2002-2019 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.repeatable;
import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
/**
* Same as {@link ExplicitPropertiesFilesRepeatedTestPropertySourceTests}, but
* with the order of the properties files reversed.
*
* @author Sam Brannen
* @since 5.2
*/
@TestPropertySource("second.properties")
@TestPropertySource("first.properties")
public class ReversedExplicitPropertiesFilesRepeatedTestPropertySourceTests extends AbstractRepeatableTestPropertySourceTests {
@Test
public void test() {
assertEnvironmentValue("alpha", "beta");
assertEnvironmentValue("first", "1111");
assertEnvironmentValue("second", "1111");
}
}

112
spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java

@ -57,23 +57,40 @@ public class TestPropertySourceUtilsTests { @@ -57,23 +57,40 @@ public class TestPropertySourceUtilsTests {
private static final String[] FOO_LOCATIONS = new String[] {"classpath:/foo.properties"};
@Test
public void emptyAnnotation() {
assertThatIllegalStateException().isThrownBy(() ->
buildMergedTestPropertySources(EmptyPropertySources.class))
.withMessageStartingWith("Could not detect default properties file for test")
assertThatIllegalStateException()
.isThrownBy(() -> buildMergedTestPropertySources(EmptyPropertySources.class))
.withMessageStartingWith("Could not detect default properties file for test class")
.withMessageContaining("class path resource")
.withMessageContaining("does not exist")
.withMessageContaining("EmptyPropertySources.properties");
}
@Test
public void extendedEmptyAnnotation() {
assertThatIllegalStateException().isThrownBy(() ->
buildMergedTestPropertySources(ExtendedEmptyPropertySources.class))
assertThatIllegalStateException()
.isThrownBy(() -> buildMergedTestPropertySources(ExtendedEmptyPropertySources.class))
.withMessageStartingWith("Could not detect default properties file for test")
.withMessageContaining("class path resource")
.withMessageContaining("does not exist")
.withMessageContaining("ExtendedEmptyPropertySources.properties");
}
@Test
public void repeatedTestPropertySourcesWithConflictingInheritLocationsFlags() {
assertThatIllegalArgumentException()
.isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritLocationsFlags.class))
.withMessageContaining("must declare the same value for 'inheritLocations' as other directly present or meta-present @TestPropertySource annotations");
}
@Test
public void repeatedTestPropertySourcesWithConflictingInheritPropertiesFlags() {
assertThatIllegalArgumentException()
.isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritPropertiesFlags.class))
.withMessageContaining("must declare the same value for 'inheritProperties' as other directly present or meta-present @TestPropertySource annotations");
}
@Test
public void value() {
assertMergedTestPropertySources(ValuePropertySources.class, asArray("classpath:/value.xml"),
@ -82,8 +99,8 @@ public class TestPropertySourceUtilsTests { @@ -82,8 +99,8 @@ public class TestPropertySourceUtilsTests {
@Test
public void locationsAndValueAttributes() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
buildMergedTestPropertySources(LocationsAndValuePropertySources.class));
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> buildMergedTestPropertySources(LocationsAndValuePropertySources.class));
}
@Test
@ -126,30 +143,37 @@ public class TestPropertySourceUtilsTests { @@ -126,30 +143,37 @@ public class TestPropertySourceUtilsTests {
@Test
public void addPropertiesFilesToEnvironmentWithNullContext() {
assertThatIllegalArgumentException().isThrownBy(() ->
addPropertiesFilesToEnvironment((ConfigurableApplicationContext) null, FOO_LOCATIONS))
.withMessageContaining("must not be null");
assertThatIllegalArgumentException()
.isThrownBy(() -> addPropertiesFilesToEnvironment((ConfigurableApplicationContext) null, FOO_LOCATIONS))
.withMessageContaining("'context' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithContextAndNullLocations() {
assertThatIllegalArgumentException().isThrownBy(() ->
addPropertiesFilesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
.withMessageContaining("must not be null");
assertThatIllegalArgumentException()
.isThrownBy(() -> addPropertiesFilesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
.withMessageContaining("'locations' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithNullEnvironment() {
assertThatIllegalArgumentException().isThrownBy(() ->
addPropertiesFilesToEnvironment((ConfigurableEnvironment) null, mock(ResourceLoader.class), FOO_LOCATIONS))
.withMessageContaining("must not be null");
assertThatIllegalArgumentException()
.isThrownBy(() -> addPropertiesFilesToEnvironment((ConfigurableEnvironment) null, mock(ResourceLoader.class), FOO_LOCATIONS))
.withMessageContaining("'environment' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithEnvironmentLocationsAndNullResourceLoader() {
assertThatIllegalArgumentException()
.isThrownBy(() -> addPropertiesFilesToEnvironment(new MockEnvironment(), null, FOO_LOCATIONS))
.withMessageContaining("'resourceLoader' must not be null");
}
@Test
public void addPropertiesFilesToEnvironmentWithEnvironmentAndNullLocations() {
assertThatIllegalArgumentException().isThrownBy(() ->
addPropertiesFilesToEnvironment(new MockEnvironment(), mock(ResourceLoader.class), (String[]) null))
.withMessageContaining("must not be null");
assertThatIllegalArgumentException()
.isThrownBy(() -> addPropertiesFilesToEnvironment(new MockEnvironment(), mock(ResourceLoader.class), (String[]) null))
.withMessageContaining("'locations' must not be null");
}
@Test
@ -172,43 +196,43 @@ public class TestPropertySourceUtilsTests { @@ -172,43 +196,43 @@ public class TestPropertySourceUtilsTests {
@Test
public void addInlinedPropertiesToEnvironmentWithNullContext() {
assertThatIllegalArgumentException().isThrownBy(() ->
addInlinedPropertiesToEnvironment((ConfigurableApplicationContext) null, KEY_VALUE_PAIR))
.withMessageContaining("context");
assertThatIllegalArgumentException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment((ConfigurableApplicationContext) null, KEY_VALUE_PAIR))
.withMessageContaining("'context' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithContextAndNullInlinedProperties() {
assertThatIllegalArgumentException().isThrownBy(() ->
addInlinedPropertiesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
.withMessageContaining("inlined");
assertThatIllegalArgumentException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment(mock(ConfigurableApplicationContext.class), (String[]) null))
.withMessageContaining("'inlinedProperties' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithNullEnvironment() {
assertThatIllegalArgumentException().isThrownBy(() ->
addInlinedPropertiesToEnvironment((ConfigurableEnvironment) null, KEY_VALUE_PAIR))
.withMessageContaining("environment");
assertThatIllegalArgumentException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment((ConfigurableEnvironment) null, KEY_VALUE_PAIR))
.withMessageContaining("'environment' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithEnvironmentAndNullInlinedProperties() {
assertThatIllegalArgumentException().isThrownBy(() ->
addInlinedPropertiesToEnvironment(new MockEnvironment(), (String[]) null))
.withMessageContaining("inlined");
assertThatIllegalArgumentException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), (String[]) null))
.withMessageContaining("'inlinedProperties' must not be null");
}
@Test
public void addInlinedPropertiesToEnvironmentWithMalformedUnicodeInValue() {
assertThatIllegalStateException().isThrownBy(() ->
addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("key = \\uZZZZ")))
assertThatIllegalStateException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("key = \\uZZZZ")))
.withMessageContaining("Failed to load test environment property");
}
@Test
public void addInlinedPropertiesToEnvironmentWithMultipleKeyValuePairsInSingleInlinedProperty() {
assertThatIllegalStateException().isThrownBy(() ->
addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("a=b\nx=y")))
assertThatIllegalStateException()
.isThrownBy(() -> addInlinedPropertiesToEnvironment(new MockEnvironment(), asArray("a=b\nx=y")))
.withMessageContaining("Failed to load exactly one test environment property");
}
@ -226,9 +250,9 @@ public class TestPropertySourceUtilsTests { @@ -226,9 +250,9 @@ public class TestPropertySourceUtilsTests {
@Test
public void convertInlinedPropertiesToMapWithNullInlinedProperties() {
assertThatIllegalArgumentException().isThrownBy(() ->
convertInlinedPropertiesToMap((String[]) null))
.withMessageContaining("inlined");
assertThatIllegalArgumentException()
.isThrownBy(() -> convertInlinedPropertiesToMap((String[]) null))
.withMessageContaining("'inlinedProperties' must not be null");
}
@ -256,6 +280,16 @@ public class TestPropertySourceUtilsTests { @@ -256,6 +280,16 @@ public class TestPropertySourceUtilsTests {
static class ExtendedEmptyPropertySources extends EmptyPropertySources {
}
@TestPropertySource(locations = "foo.properties", inheritLocations = false)
@TestPropertySource(locations = "bar.properties", inheritLocations = true)
static class RepeatedPropertySourcesWithConflictingInheritLocationsFlags {
}
@TestPropertySource(properties = "a = b", inheritProperties = false)
@TestPropertySource(properties = "x = y", inheritProperties = true)
static class RepeatedPropertySourcesWithConflictingInheritPropertiesFlags {
}
@TestPropertySource(locations = "/foo", value = "/bar")
static class LocationsAndValuePropertySources {
}

1
spring-test/src/test/resources/log4j2-test.xml

@ -25,6 +25,7 @@ @@ -25,6 +25,7 @@
<Logger name="org.springframework.test.context.support.DelegatingSmartContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.AbstractGenericContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.AnnotationConfigContextLoader" level="info" />
<Logger name="org.springframework.test.context.support.TestPropertySourceUtils" level="trace" />
<Logger name="org.springframework.beans" level="warn" />
<Logger name="org.springframework.test.web.servlet.result" level="debug" />
-->

1
spring-test/src/test/resources/org/springframework/test/context/env/repeatable/DefaultPropertiesFileDetectionRepeatedTestPropertySourceTests.properties vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
default.value = default file

3
spring-test/src/test/resources/org/springframework/test/context/env/repeatable/first.properties vendored

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
alpha = beta
first = 1111
second = 1111

1
spring-test/src/test/resources/org/springframework/test/context/env/repeatable/local.properties vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
key1 = local file

1
spring-test/src/test/resources/org/springframework/test/context/env/repeatable/meta.properties vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
key2 = meta file

2
spring-test/src/test/resources/org/springframework/test/context/env/repeatable/second.properties vendored

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
alpha = omega
second = 2222

19
src/docs/asciidoc/testing.adoc

@ -688,6 +688,7 @@ The following example demonstrates how to declare inlined properties: @@ -688,6 +688,7 @@ The following example demonstrates how to declare inlined properties:
----
<1> Declare `timezone` and `port` properties.
See <<testcontext-ctx-management-property-sources>> for examples and further details.
[[spring-testing-annotation-dirtiescontext]]
===== `@DirtiesContext`
@ -2841,6 +2842,24 @@ The following example sets two inlined properties: @@ -2841,6 +2842,24 @@ The following example sets two inlined properties:
----
<1> Setting two properties by using two variations of the key-value syntax.
[NOTE]
====
As of Spring Framework 5.2, `@TestPropertySource` can be used as _repeatable annotation_.
That means that you can have multiple declarations of `@TestPropertySource` on a single
test class, with the `locations` and `properties` from later `@TestPropertySource`
annotations overriding those from previous `@TestPropertySource` annotations.
In addition, you may declare multiple composed annotations on a test class that are each
meta-annotated with `@TestPropertySource`, and all of those `@TestPropertySource`
declarations will contribute to your test property sources.
Directly present `@TestPropertySource` annotations always take precedence over
meta-present `@TestPropertySource` annotations. In other words, `locations` and
`properties` from a directly present `@TestPropertySource` annotation will override the
`locations` and `properties` from a `@TestPropertySource` annotation used as a
meta-annotation.
====
====== Default Properties File Detection

Loading…
Cancel
Save