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
Prior to this commit, inlined properties could only be supplied as an
array of Strings as follows.
@TestPropertySource(properties = {
"key1 = value1",
"key2 = value2"
})
Although a user could supply a text block, it was previously rejected
due to a "single key-value pair per string" check in
TestPropertySourceUtils.convertInlinedPropertiesToMap(String...).
This commit removes that restriction and allows the above example to be
refactored to use a text block as follows.
@TestPropertySource(properties = """
key1 = value1
key2 = value2
"""
)
Closes gh-31053
Prior to this commit, property files configured (or inferred) via
@TestPropertySource were read using the default encoding of the JVM.
This commit introduces an `encoding` attribute in @TestPropertySource
which allows developers to specify an explicit encoding for test
property files.
Closes gh-30982
Spring Framework 4.3 introduced the `PropertySourceFactory` SPI for use
with `@PropertySource` on `@Configuration` classes; however, prior to
this commit there was no mechanism to support custom properties file
formats in `@TestPropertySource` for integration tests.
This commit introduces support for configuring a custom
`PropertySourceFactory` via a new `factory` attribute in
`@TestPropertySource` in order to support custom file formats such as
JSON, YAML, etc.
For example, if you create a YamlPropertySourceFactory, you can use it
in integration tests as follows.
@SpringJUnitConfig
@TestPropertySource(locations = "/test.yaml", factory = YamlPropertySourceFactory.class)
class MyTestClass { /* ... /* }
If a custom factory is not specified, traditional `*.properties` and
`*.xml` based `java.util.Properties` file formats are supported, which
was the existing behavior.
Closes gh-30981
Prior to this commit, if an error was encountered during build-time AOT
processing, the error was logged at WARN/DEBUG level, and processing
continued.
With this commit, test AOT processing now fails on error by default. In
addition, the `failOnError` mode can be disabled by setting the
`spring.test.aot.processing.failOnError` Spring/System property to
`false`.
Closes gh-30977
Prior to this commit, test AOT processing failed if a feature name for
generated class names was used for more than one ApplicationContext.
For example, when generating code for org.example.MessageService with a
"Management" feature name, the "BeanDefinitions" class was named as
follows (without a uniquely identifying TestContext###_ feature name
prefix).
org/example/MessageService__ManagementBeanDefinitions.java
When another attempt was made to generate code for the MessageService
using the same "Management" feature name, a FileAlreadyExistsException
was thrown denoting that the class/file name was already in use.
To avoid such naming collisions, this commit introduces a
TestContextGenerationContext which provides a custom implementation of
withName(String) that prepends an existing feature name (if present) to
a new feature name, thereby treating any existing feature name as a
prefix to a new, nested feature name.
Consequently, code generation for the above example now results in
unique class/file names like the following (which retain the uniquely
identifying TestContext###_ prefixes).
org/example/MessageService__TestContext002_ManagementBeanDefinitions.java
org/example/MessageService__TestContext003_ManagementBeanDefinitions.java
Closes gh-30861
Prior to this commit, the required runtime dependencies were checked
via reflection each time an attempt was made to instantiate
MicrometerObservationRegistryTestExecutionListener.
Since it's sufficient to check for the presence of required runtime
dependencies only once, this commit caches the results of the
dependency checks in a static field.
This commit also introduces automated tests for the runtime dependency
checks in MicrometerObservationRegistryTestExecutionListener.
See gh-30747
This commit overhauls the TestExecutionListener for Micrometer's
ObservationRegistry that was introduced in the previous commit.
Specifically, this commit:
- Renames the listener to MicrometerObservationRegistryTestExecutionListener
since the use of a ThreadLocal is an implementation detail that may
change over time.
- Makes the listener package-private instead of public in order to
allow the team greater flexibility in evolving this feature.
- Eagerly loads the ObservationThreadLocalAccessor class and verifies
that it has a getObservationRegistry() method to ensure that the
listener is properly skipped when SpringFactoriesLoader attempts to
load it, if Micrometer 1.10.8+ is not on the classpath.
- Switches the listener's automatic registration order to 2500 in order
to register it after the DependencyInjectionTestExecutionListener.
- Only tracks the previous ObservationRegistry in beforeTestMethod() if
the test's ApplicationContext contains an ObservationRegistry bean.
- Properly removes the TestContext attribute for the previous
ObservationRegistry in afterTestMethod().
- Introduces DEBUG logging for diagnostics.
- Adds an entry in the Javadoc for TestExecutionListener as well as in
the Testing chapter in the reference manual.
Closes gh-30658
Prior to this commit, there was no way to specify the
ObservationRegistry that is registered in the given test's
ApplicationContext as the one that should be used by Micrometer's
ObservationThreadLocalAccessor for context propagation.
This commit introduces a TestExecutionListener for Micrometer's
ObservationRegistry in the Spring TestContext Framework. Specifically,
this listener obtains the ObservationRegistry registered in the test's
ApplicationContext, stores it in ObservationThreadLocalAccessor for the
duration of each test method execution, and restores the original
ObservationRegistry in ObservationThreadLocalAccessor after each test.
Co-authored-by: Sam Brannen <sam@sambrannen.com>
See gh-30658
In the previous commit which introduced the new context failure threshold
support in the TestContext framework, the context failure tracking was
tied to an instance of DefaultCacheAwareContextLoaderDelegate.
Consequently, the feature was only supported within a given test class.
This commit therefore moves context failure tracking to the ContextCache
SPI (and DefaultContextCache) so that the feature applies to all test
classes within the current test suite (i.e., JVM).
This commit also includes the total failure count in the statistics
logged by the DefaultContextCache.
See gh-14182
This commit introduces initial support for a new "context failure
threshold" feature in the Spring TestContext Framework (TCF).
Specifically, DefaultCacheAwareContextLoaderDelegate now tracks how
many times a failure occurs when attempting to load an
ApplicationContext and preemptively throws an IllegalStateException for
subsequent attempts to load the same context if the configured failure
threshold has been exceeded.
See gh-14182
This commit refines how GraalVM tracing agent detection works
for both test and application executions.
It rolls back the introduction of TestAotDetector done in 111309605c
and instead updates AotDetector.useGeneratedArtifacts()
to only detect "buildtime" and "runtime" imagecode system
property values by leveraging a new method
NativeDetector.inNativeImage(NativeDetector.Context...).
This commit also adds a workaround for
https://github.com/oracle/graal/issues/6691.
Closes gh-30511
Prior to this commit, the SpringExtension looked up the
TestInstance.Lifecycle and ExecutionMode using
TestContextAnnotationUtils; however, using TestContextAnnotationUtils is
problematic since the TestInstance.Lifecycle and ExecutionMode can be
configured globally via configuration parameters instead of locally via
the @TestInstance and @Execution annotations.
This commit addresses these issues by looking up the
TestInstance.Lifecycle and ExecutionMode via JUnit Jupiter's
ExtensionContext which takes into account both global and local
configuration.
See gh-30020
Prior to this commit, test AOT processing failed when using the GraalVM
tracing agent and GraalVM Native Build Tools (NBT) plugins for Maven
and Gradle.
The reason is that the AOT support in the TestContext framework (TCF)
relied on AotDetector.useGeneratedArtifacts() which delegates
internally to NativeDetector.inNativeImage() which does not
differentiate between values stored in the
"org.graalvm.nativeimage.imagecode" JVM system property.
This commit addresses this issue by introducing a TestAotDetector
utility that is specific to the TCF. This detector considers the
current runtime to be in "AOT runtime mode" if the "spring.aot.enabled"
Spring property is set to "true" or the GraalVM
"org.graalvm.nativeimage.imagecode" JVM system property is set to any
non-empty value other than "agent".
Closes gh-30281
This commit modifies the way the `@RecordApplicationEvents` annotation
works in tests, allowing for capture of events from threads other than
the main test thread (async events) and for the assertion of captured
event from a separate thread (e.g. when using `Awaitility`).
This is done by switching the `ApplicationEventsHolder` to use an
`InheritedThreadLocal`.
There is a mutual exclusion between support of asynchronous events vs
support of JUnit5 parallel tests with the `@TestInstance(PER_CLASS)`
mode. As a result, we favor the former and now `SpringExtension` will
invalidate a test class that is annotated (or meta-annotated, or
enclosed-annotated) with `@RecordApplicationEvents` AND
`@TestInstance(PER_CLASS)` AND `@Execution(CONCURRENT)`.
See gh-29827
Closes gh-30020
ServletContext has sets of major/minor version properties that we have
not updated in MockServletContext in several years.
Since we upgraded the baseline to Servlet 6.0 in Spring Framework 6.0,
now seems like a good time to update those version properties.
Closes gh-30395