Since we now officially support the TEST_METHOD ExtensionContextScope
(see gh-35676 and gh-35680), this commit introduces tests which
demonstrate that the issue raised in gh-34576 is no longer an "issue" if
the user indirectly configures the SpringExtension to use the TEST_METHOD
scope via the "junit.jupiter.extensions.testinstantiation.extensioncontextscope.default"
configuration parameter.
Historically, @Autowired fields in an enclosing class of a @Nested
test class have been injected from the ApplicationContext for the
enclosing class. If the enclosing test class and @Nested test class
share the same ApplicationContext configuration, things work as
developers expect. However, if the enclosing class and @Nested test
class have different ApplicationContexts, that can lead to
difficult-to-debug scenarios. For example, a bean injected into the
enclosing test class will not participate in a test-managed transaction
in the @Nested test class (see gh-34576).
JUnit Jupiter 5.12 introduced a new ExtensionContextScope feature which
allows the SpringExtension to behave the same for @Autowired fields as
it already does for @Autowired arguments in lifecycle and test
methods. Specifically, if a developer sets the ExtensionContextScope to
TEST_METHOD — for example, by configuring the following configuration
parameter as a JVM system property or in a `junit-platform.properties`
file — the SpringExtension already supports dependency injection from
the current, @Nested ApplicationContext in @Autowired fields in an
enclosing class of the @Nested test class.
junit.jupiter.extensions.testinstantiation.extensioncontextscope.default=test_method
However, there are two scenarios that fail as of Spring Framework
6.2.12.
1. @TestConstructor configuration in @Nested class hierarchies.
2. Field injection for bean overrides (such as @MockitoBean) in
@Nested class hierarchies.
Commit 82c34f7b51 fixed the SpringExtension to support scenario #2
above.
To fix scenario #1, this commit revises
BeanOverrideTestExecutionListener's injectField() implementation to
look up the fields to inject for the "current test instance" instead of
for the "current test class".
This commit also introduces tests for both scenarios.
See gh-34576
See gh-35676
Closes gh-35680
This commit introduces a new isAutowirableConstructor(Executable, PropertyProvider)
overload in TestConstructorUtils and deprecates all other existing variants
for removal in 7.1.
Closes gh-35676
This commit removes JSpecify (TYPE_USE) annotations on
org.hamcrest.Matcher parameters to prevent a related
"Cannot attach type annotations" error when Hamcrest
(optional dependency) is not in the classpath with Java > 22.
Closes gh-35666
Compose consumers and apply them together from the build method
to allow multiple parties to supply consumers that collaborate
on the same HttpMessageConverters.Builder.
See gh-35578
Prior to this commit, the BeanOverrideBeanFactoryPostProcessor rejected
any attempt to override a non-singleton bean; however, due to interest
from the community, we have decided to provide support for overriding
non-singleton beans via the Bean Override mechanism — for example, when
using @MockitoBean, @MockitoSpyBean, and @TestBean.
With this commit, we now support Bean Overrides for non-singletons: for
standard JVM runtimes as well as AOT processing and AOT runtimes. This
commit also documents that non-singletons will effectively be converted
to singletons when overridden and logs a warning similar to the
following.
WARN: BeanOverrideBeanFactoryPostProcessor - Converting 'prototype' scoped bean definition 'myBean' to a singleton.
See gh-33602
See gh-32933
See gh-33800
Closes gh-35574
At some point, TestNG started implementing listener methods as interface
default methods, so we no longer need to override those methods with
empty implementations.
Prior to this commit, AbstractTestNGSpringContextTests was not
thread-safe with regard to tracked exceptions.
To address that, AbstractTestNGSpringContextTests now tracks the test
exception via a ThreadLocal.
Closes gh-35528
Since Spring Framework 4.2, DefaultContextCache supported an LRU (least
recently used) eviction policy via a custom LruCache which extended
LinkedHashMap. The LruCache reacted to LinkedHashMap's
removeEldestEntry() callback to remove the LRU context if the maxSize
of the cache was exceeded.
Due to the nature of the implementation in LinkedHashMap, the
removeEldestEntry() callback is invoked after a new entry has been
stored to the map.
Consequently, a Spring ApplicationContext (C1) was evicted from the
cache after a new context (C2) was loaded and added to the cache,
leading to failure scenarios such as the following.
- C1 and C2 share an external resource -- for example, a database.
- C2 initializes the external resource with test data when C2 is loaded.
- C1 cleans up the external resource when C1 is closed.
- C1 is loaded and added to the cache.
- C2 is loaded and added to the cache before C1 is evicted.
- C1 is evicted and closed.
- C2 tests fail, because C1 removed test data required for C2.
To address such scenarios, this commit replaces the custom LruCache
with custom LRU eviction logic in DefaultContextCache and revises
the put(MergedContextConfiguration, ApplicationContext) method to
delegate to a new evictLruContextIfNecessary() method.
This commit also introduces a new put(MergedContextConfiguration,
LoadFunction) method in the ContextCache API which is overridden by
DefaultContextCache to ensure that an evicted context is removed and
closed before a new context is loaded to take its place in the cache.
In addition, DefaultCacheAwareContextLoaderDelegate has been revised to
make use of the new put(MergedContextConfiguration, LoadFunction) API.
Closes gh-21007