diff --git a/framework-docs/modules/ROOT/nav.adoc b/framework-docs/modules/ROOT/nav.adoc index dbf0c19d5f4..867a49c5b46 100644 --- a/framework-docs/modules/ROOT/nav.adoc +++ b/framework-docs/modules/ROOT/nav.adoc @@ -134,13 +134,13 @@ **** xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[] **** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[] *** xref:testing/testcontext-framework/fixture-di.adoc[] +*** xref:testing/testcontext-framework/bean-overriding.adoc[] *** xref:testing/testcontext-framework/web-scoped-beans.adoc[] *** xref:testing/testcontext-framework/tx.adoc[] *** xref:testing/testcontext-framework/executing-sql.adoc[] *** xref:testing/testcontext-framework/parallel-test-execution.adoc[] *** xref:testing/testcontext-framework/support-classes.adoc[] *** xref:testing/testcontext-framework/aot.adoc[] -*** xref:testing/testcontext-framework/bean-overriding.adoc[] ** xref:testing/webtestclient.adoc[] ** xref:testing/spring-mvc-test-framework.adoc[] *** xref:testing/spring-mvc-test-framework/server.adoc[] @@ -172,6 +172,8 @@ ***** xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[] ***** xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[] ***** xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[] +***** xref:testing/annotations/integration-spring/annotation-testbean.adoc[] +***** xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[] ***** xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[] ***** xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[] ***** xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[] @@ -184,8 +186,6 @@ ***** xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[] ***** xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[] ***** xref:testing/annotations/integration-spring/annotation-disabledinaotmode.adoc[] -***** xref:testing/annotations/integration-spring/annotation-testbean.adoc[] -***** xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[] **** xref:testing/annotations/integration-junit4.adoc[] **** xref:testing/annotations/integration-junit-jupiter.adoc[] **** xref:testing/annotations/integration-meta.adoc[] diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring.adoc index 0d7eaaff63d..300c32dc891 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring.adoc @@ -16,6 +16,8 @@ Spring's testing annotations include the following: * xref:testing/annotations/integration-spring/annotation-activeprofiles.adoc[`@ActiveProfiles`] * xref:testing/annotations/integration-spring/annotation-testpropertysource.adoc[`@TestPropertySource`] * xref:testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc[`@DynamicPropertySource`] +* xref:testing/annotations/integration-spring/annotation-testbean.adoc[`@TestBean`] +* xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[`@MockitoBean` and `@MockitoSpyBean`] * xref:testing/annotations/integration-spring/annotation-dirtiescontext.adoc[`@DirtiesContext`] * xref:testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc[`@TestExecutionListeners`] * xref:testing/annotations/integration-spring/annotation-recordapplicationevents.adoc[`@RecordApplicationEvents`] @@ -28,6 +30,4 @@ Spring's testing annotations include the following: * xref:testing/annotations/integration-spring/annotation-sqlmergemode.adoc[`@SqlMergeMode`] * xref:testing/annotations/integration-spring/annotation-sqlgroup.adoc[`@SqlGroup`] * xref:testing/annotations/integration-spring/annotation-disabledinaotmode.adoc[`@DisabledInAotMode`] -* xref:testing/annotations/integration-spring/annotation-testbean.adoc[`@TestBean`] -* xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[`@MockitoBean` and `@MockitoSpyBean`] diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc index c1270dff19e..ad79e64820b 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc @@ -1,24 +1,24 @@ [[spring-testing-annotation-beanoverriding-mockitobean]] = `@MockitoBean` and `@MockitoSpyBean` -`@MockitoBean` and `@MockitoSpyBean` are used on a test class field to override a bean -with a mocking and spying instance, respectively. In the later case, the original bean -definition is not replaced but instead an early instance is captured and wrapped by the -spy. +`@MockitoBean` and `@MockitoSpyBean` are used on test class fields to override beans in +the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the latter +case, the original bean definition is not replaced, but instead an early instance of the +bean is captured and wrapped by the spy. By default, the name of the bean to override is derived from the annotated field's name, -but both annotations allows for a specific `name` to be provided. Each annotation also +but both annotations allow for a specific `name` to be provided. Each annotation also defines Mockito-specific attributes to fine-tune the mocking details. -The `@MockitoBean` annotation uses the `CREATE_OR_REPLACE_DEFINITION` +The `@MockitoBean` annotation uses the `REPLACE_OR_CREATE_DEFINITION` xref:testing/testcontext-framework/bean-overriding.adoc#spring-testing-beanoverriding-extending[strategy for test bean overriding]. -The `@MockitoSpyBean` annotation uses the `WRAP_EARLY_BEAN` -xref:testing/testcontext-framework/bean-overriding.adoc#spring-testing-beanoverriding-extending[strategy] +The `@MockitoSpyBean` annotation uses the `WRAP_BEAN` +xref:testing/testcontext-framework/bean-overriding.adoc#spring-testing-beanoverriding-extending[strategy], and the original instance is wrapped in a Mockito spy. -The following example shows how to configure the bean name for both `@MockitoBean` and -`@MockitoSpyBean` annotations: +The following example shows how to configure the bean name via `@MockitoBean` and +`@MockitoSpyBean`: [tabs] ====== @@ -27,6 +27,7 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { + @MockitoBean(name = "service1") // <1> private CustomService mockService; @@ -36,7 +37,7 @@ Java:: // test case body... } ---- -<1> Mark `mockService` as a Mockito mock override of bean `service1` in this test class -<2> Mark `spyService` as a Mockito spy override of bean `service2` in this test class -<3> Both fields will be injected with the Mockito values (the mock and the spy respectively) -====== \ No newline at end of file +<1> Mark `mockService` as a Mockito mock override of bean `service1` in this test class. +<2> Mark `spyService` as a Mockito spy override of bean `service2` in this test class. +<3> The fields will be injected with the Mockito mock and spy, respectively. +====== diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc index 4c8117f59f4..8889ca73eb8 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc @@ -1,17 +1,18 @@ [[spring-testing-annotation-beanoverriding-testbean]] = `@TestBean` -`@TestBean` is used on a test class field to override a specific bean with an instance -provided by a conventionally named static factory method. +`@TestBean` is used on a test class field to override a specific bean in the test's +`ApplicationContext` with an instance provided by a conventionally named static factory +method. By default, the bean name and the associated factory method name are derived from the -annotated field's name but the annotation allows for specific values to be provided. +annotated field's name, but the annotation allows for specific values to be provided. The `@TestBean` annotation uses the `REPLACE_DEFINITION` xref:testing/testcontext-framework/bean-overriding.adoc#spring-testing-beanoverriding-extending[strategy for test bean overriding]. The following example shows how to fully configure the `@TestBean` annotation, with -explicit values equivalent to the default: +explicit values equivalent to the defaults: [tabs] ====== @@ -30,10 +31,9 @@ Java:: } } ---- -<1> Mark a field for bean overriding in this test class -<2> The result of this static method will be used as the instance and injected into the field +<1> Mark a field for bean overriding in this test class. +<2> The result of this static method will be used as the instance and injected into the field. ====== -NOTE: The method to invoke is searched in the test class and any enclosing class it might -have, as well as its hierarchy. This typically allows nested test class to rely on the -factory method in the root test class. \ No newline at end of file +NOTE: Spring searches for the factory method to invoke in the test class, in the test +class hierarchy, and in the enclosing class hierarchy for a `@Nested` test class. diff --git a/framework-docs/modules/ROOT/pages/testing/testcontext-framework/bean-overriding.adoc b/framework-docs/modules/ROOT/pages/testing/testcontext-framework/bean-overriding.adoc index a5e384fdd0e..92e6f3d975a 100644 --- a/framework-docs/modules/ROOT/pages/testing/testcontext-framework/bean-overriding.adoc +++ b/framework-docs/modules/ROOT/pages/testing/testcontext-framework/bean-overriding.adoc @@ -1,53 +1,67 @@ -[[spring-testing-beanoverriding]] +[[testcontext-bean-overriding]] = Bean Overriding in Tests -Bean Overriding in Tests refers to the ability to override specific beans in the Context -for a test class, by annotating one or more fields in said test class. +Bean overriding in tests refers to the ability to override specific beans in the +`ApplicationContext` for a test class, by annotating one or more fields in the test class. -NOTE: This is intended as a less risky alternative to the practice of registering a bean via -`@Bean` with the `DefaultListableBeanFactory` `setAllowBeanDefinitionOverriding` set to -`true`. +NOTE: This feature is intended as a less risky alternative to the practice of registering +a bean via `@Bean` with the `DefaultListableBeanFactory` +`setAllowBeanDefinitionOverriding` flag set to `true`. -The Spring Testing Framework provides two sets of annotations: -xref:testing/annotations/integration-spring/annotation-testbean.adoc[`@TestBean`], -xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[`@MockitoBean` and -`@MockitoSpyBean`]. The former relies purely on Spring, while the later set relies on -the https://site.mockito.org/[Mockito] third party library. +The Spring TestContext framework provides two sets of annotations for bean overriding. -[[spring-testing-beanoverriding-extending]] -== Extending bean override with a custom annotation +* xref:testing/annotations/integration-spring/annotation-testbean.adoc[`@TestBean`] +* xref:testing/annotations/integration-spring/annotation-mockitobean.adoc[`@MockitoBean` and `@MockitoSpyBean`] -The three annotations mentioned above build upon the `@BeanOverride` meta-annotation -and associated infrastructure, which allows to define custom bean overriding variants. +The former relies purely on Spring, while the latter set relies on the +https://site.mockito.org/[Mockito] third-party library. -To create an extension, the following is needed: +[[testcontext-bean-overriding-custom]] +== Custom Bean Override Support -- An annotation meta-annotated with `@BeanOverride` that defines the -`BeanOverrideProcessor` to use. -- The `BeanOverrideProcessor` implementation itself. -- One or more concrete `OverrideMetadata` implementations provided by the processor. +The three annotations mentioned above build upon the `@BeanOverride` meta-annotation and +associated infrastructure, which allows one to define custom bean overriding variants. -The Spring TestContext Framework includes infrastructure classes that support bean -overriding: a `BeanFactoryPostProcessor`, a `TestExecutionListener` and a -`ContextCustomizerFactory`. -The later two are automatically registered via the Spring TestContext Framework -`spring.factories` file, and are responsible for setting up the rest of the infrastructure. +To create custom bean override support, the following is needed: -The test classes are parsed looking for any field meta-annotated with `@BeanOverride`, -instantiating the relevant `BeanOverrideProcessor` in order to register an -`OverrideMetadata`. +* An annotation meta-annotated with `@BeanOverride` that defines the + `BeanOverrideProcessor` to use +* A custom `BeanOverrideProcessor` implementation +* One or more concrete `OverrideMetadata` implementations provided by the processor -Then the `BeanOverrideBeanFactoryPostProcessor` will use that information to alter the -context, registering and replacing bean definitions as defined by each metadata -`BeanOverrideStrategy`: +The Spring TestContext framework includes implementations of the following APIs that +support bean overriding and are responsible for setting up the rest of the infrastructure. -- `REPLACE_DEFINITION`: replaces the bean definition. If it is not present in the -context, an exception is thrown. -- `CREATE_OR_REPLACE_DEFINITION`: replaces the bean definition if the bean definition -does not exist, or create one if it is not. -- `WRAP_BEAN`: get the original instance early so that it can be wrapped. +* a `BeanFactoryPostProcessor` +* a `ContextCustomizerFactory` +* a `TestExecutionListener` -NOTE: The Bean Overriding infrastructure does not include any bean resolution step, -unlike an `@Autowired`-annotated field for instance. As such, the name of the bean to -override must be somehow provided to or computed by the `BeanOverrideProcessor`. -Typically, the user provides the name one way or the other. \ No newline at end of file +The `spring-test` module registers implementations of the latter two +(`BeanOverrideContextCustomizerFactory` and `BeanOverrideTestExecutionListener`) in its +{spring-framework-code}/spring-test/src/main/resources/META-INF/spring.factories[`META-INF/spring.factories` +properties file]. + +The bean overriding infrastructure searches in test classes for any field meta-annotated +with `@BeanOverride` and instantiates the corresponding `BeanOverrideProcessor` which is +responsible for registering appropriate `OverrideMetadata`. + +The internal `BeanOverrideBeanFactoryPostProcessor` then uses that information to alter +the test's `ApplicationContext` by registering and replacing bean definitions as defined +by the corresponding `BeanOverrideStrategy`: + +* `REPLACE_DEFINITION`: Replaces the bean definition. Throws an exception if a + corresponding bean definition does not exist. +* `REPLACE_OR_CREATE_DEFINITION`: Replaces the bean definition if it exists. Creates a + new bean definition if a corresponding bean definition does not exist. +* `WRAP_BEAN`: Retrieves the original bean instance and wraps it. + +[NOTE] +==== +In contrast to Spring's autowiring mechanism (for example, resolution of an `@Autowired` +field), the bean overriding infrastructure in the TestContext framework does not perform +any heuristics to locate a bean. Instead, the name of the bean to override must be +explicitly provided to or computed by the `BeanOverrideProcessor`. + +Typically, the user provides the bean name via a custom annotation, or the +`BeanOverrideProcessor` determines the bean name based on some convention. +==== diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverride.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverride.java index a92c19c9da6..f5be7dd7775 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverride.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverride.java @@ -22,25 +22,23 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Mark an annotation as eligible for Bean Override processing. + * Mark a composed annotation as eligible for Bean Override processing. * - *

Specifying this annotation triggers the defined {@link BeanOverrideProcessor} + *

Specifying this annotation triggers the configured {@link BeanOverrideProcessor} * which must be capable of handling the composed annotation and its attributes. * - *

The composed annotation is meant to be detected on fields only so it is - * expected that it has a {@code Target} of {@link ElementType#FIELD FIELD}. + *

Since the composed annotation should only be applied to fields, it is + * expected that it has a {@link Target} of {@link ElementType#FIELD FIELD}. * * @author Simon Baslé * @since 6.2 - * @see BeanOverrideBeanFactoryPostProcessor */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface BeanOverride { /** - * The {@link BeanOverrideProcessor} implementation to trigger against - * the composed annotation. + * The {@link BeanOverrideProcessor} implementation to use. */ Class value(); diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java index dc52c828b32..a518fcf6c2a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java @@ -41,7 +41,7 @@ import org.springframework.util.StringUtils; /** * A {@link BeanFactoryPostProcessor} implementation that processes test classes - * and adapt the {@link BeanFactory} for any {@link BeanOverride} it may define. + * and adapts the {@link BeanFactory} for any {@link BeanOverride} it may define. * *

A set of classes from which to parse {@link OverrideMetadata} must be * provided to this processor. Each test class is expected to use any @@ -51,7 +51,7 @@ import org.springframework.util.StringUtils; * *

The provided classes are fully parsed at creation to build a metadata set. * This processor implements several {@link BeanOverrideStrategy overriding - * strategy} and chooses the correct one according to each override metadata + * strategies} and chooses the correct one according to each override metadata's * {@link OverrideMetadata#getStrategy()} method. Additionally, it provides * support for injecting the overridden bean instances into their corresponding * annotated {@link Field fields}. @@ -61,7 +61,6 @@ import org.springframework.util.StringUtils; */ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered { - private final BeanOverrideRegistrar overrideRegistrar; @@ -195,14 +194,13 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, static final class WrapEarlyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor, PriorityOrdered { - private final BeanOverrideRegistrar overrideRegistrar; + private final Map earlyReferences = new ConcurrentHashMap<>(16); - private final Map earlyReferences; + private final BeanOverrideRegistrar overrideRegistrar; private WrapEarlyBeanPostProcessor(BeanOverrideRegistrar registrar) { this.overrideRegistrar = registrar; - this.earlyReferences = new ConcurrentHashMap<>(16); } diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizer.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizer.java index 4c1d9440f16..2f16992b472 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizer.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizer.java @@ -69,6 +69,7 @@ class BeanOverrideContextCustomizer implements ContextCustomizer { private static void addInfrastructureBeanDefinition(BeanDefinitionRegistry registry, Class clazz, String beanName, Consumer constructorArgumentsConsumer) { + if (!registry.containsBeanDefinition(beanName)) { RootBeanDefinition definition = new RootBeanDefinition(clazz); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideParsingUtils.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideParsingUtils.java index e9156cecbc4..3c0984ec8c8 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideParsingUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideParsingUtils.java @@ -84,12 +84,11 @@ abstract class BeanOverrideParsingUtils { private static void parseField(Field field, Class testClass, Set metadataSet) { AtomicBoolean overrideAnnotationFound = new AtomicBoolean(); MergedAnnotations.from(field, DIRECT).stream(BeanOverride.class).forEach(mergedAnnotation -> { - Assert.state(mergedAnnotation.isMetaPresent(), "@BeanOverride annotation must be meta-present"); + MergedAnnotation metaSource = mergedAnnotation.getMetaSource(); + Assert.state(metaSource != null, "@BeanOverride annotation must be meta-present"); BeanOverride beanOverride = mergedAnnotation.synthesize(); BeanOverrideProcessor processor = BeanUtils.instantiateClass(beanOverride.value()); - MergedAnnotation metaSource = mergedAnnotation.getMetaSource(); - Assert.state(metaSource != null, "Meta-annotation source must not be null"); Annotation composedAnnotation = metaSource.synthesize(); Assert.state(overrideAnnotationFound.compareAndSet(false, true), diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideProcessor.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideProcessor.java index 1262c11c4b4..4cca2c8c260 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideProcessor.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideProcessor.java @@ -20,11 +20,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** - * Strategy interface for Bean Override processing, providing an + * Strategy interface for Bean Override processing, providing * {@link OverrideMetadata} that drives how the target bean is overridden. * - *

At least one composed annotations meta-annotated with - * {@link BeanOverride @BeanOverride}) is a companion of this processor and + *

At least one composed annotation that is meta-annotated with + * {@link BeanOverride @BeanOverride} must be a companion of this processor and * may provide additional user settings that drive how the concrete * {@link OverrideMetadata} is configured. * diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideRegistrar.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideRegistrar.java index 6c4e2cf8acc..e8a8bfd30d1 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideRegistrar.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideRegistrar.java @@ -41,23 +41,22 @@ import org.springframework.util.StringUtils; */ class BeanOverrideRegistrar implements BeanFactoryAware { - private final Map beanNameRegistry; + private final Map beanNameRegistry = new HashMap<>(); - private final Map earlyOverrideMetadata; + private final Map earlyOverrideMetadata = new HashMap<>(); private final Set overrideMetadata; @Nullable private ConfigurableBeanFactory beanFactory; + /** * Create a new registrar and immediately parse the provided classes. * @param classesToParse the initial set of classes that have been * detected to contain bean overriding annotations */ BeanOverrideRegistrar(Set> classesToParse) { - this.beanNameRegistry = new HashMap<>(); - this.earlyOverrideMetadata = new HashMap<>(); this.overrideMetadata = BeanOverrideParsingUtils.parse(classesToParse); } @@ -71,7 +70,7 @@ class BeanOverrideRegistrar implements BeanFactoryAware { } /** - * Return the detected {@link OverrideMetadata} instances. + * Get the detected {@link OverrideMetadata} instances. */ Set getOverrideMetadata() { return this.overrideMetadata; @@ -85,16 +84,16 @@ class BeanOverrideRegistrar implements BeanFactoryAware { Object wrapIfNecessary(Object bean, String beanName) throws BeansException { OverrideMetadata metadata = this.earlyOverrideMetadata.get(beanName); if (metadata != null && metadata.getStrategy() == BeanOverrideStrategy.WRAP_BEAN) { - bean = metadata.createOverride(beanName, null, bean); Assert.state(this.beanFactory != null, "ConfigurableBeanFactory must not be null"); + bean = metadata.createOverride(beanName, null, bean); metadata.track(bean, this.beanFactory); } return bean; } /** - * Register the provided {@link OverrideMetadata} and associate it with a - * {@code beanName}. + * Register the provided {@link OverrideMetadata} and associate it with the + * supplied {@code beanName}. */ void registerNameForMetadata(OverrideMetadata metadata, String beanName) { this.beanNameRegistry.put(metadata, beanName); @@ -119,7 +118,7 @@ class BeanOverrideRegistrar implements BeanFactoryAware { try { ReflectionUtils.makeAccessible(field); Object existingValue = ReflectionUtils.getField(field, target); - Assert.state(this.beanFactory != null, "beanFactory must not be null"); + Assert.state(this.beanFactory != null, "ConfigurableBeanFactory must not be null"); Object bean = this.beanFactory.getBean(beanName, field.getType()); if (existingValue == bean) { return; diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideStrategy.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideStrategy.java index 315be3174c0..42cca189965 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideStrategy.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideStrategy.java @@ -35,7 +35,7 @@ public enum BeanOverrideStrategy { /** * Replace or create a given bean definition, immediately preparing a * singleton instance. - *

Contrary to {@link #REPLACE_DEFINITION} this create a new bean + *

Contrary to {@link #REPLACE_DEFINITION}, this creates a new bean * definition if the target bean definition does not exist rather than * failing. */ @@ -43,8 +43,9 @@ public enum BeanOverrideStrategy { /** * Intercept and process an early bean reference rather than a bean - * definition, allowing variants of bean overriding to wrap the instance. - * For instance, to delegate to actual methods in the context of a mocking "spy". + * definition, allowing variants of bean overriding to wrap the instance + * — for example, to delegate to actual methods in the context of a + * mocking "spy". */ WRAP_BEAN diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java index 18c53f2338d..e84b65cf422 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java @@ -20,15 +20,13 @@ import java.lang.reflect.Field; import java.util.function.BiConsumer; import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestExecutionListener; import org.springframework.test.context.support.AbstractTestExecutionListener; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.util.ReflectionUtils; /** - * {@link TestExecutionListener} implementation that enables Bean Override - * support in tests, injecting overridden beans in appropriate fields of the - * test instance. + * {@code TestExecutionListener} that enables Bean Override support in tests, + * injecting overridden beans in appropriate fields of the test instance. * * @author Simon Baslé * @since 6.2 @@ -54,9 +52,9 @@ public class BeanOverrideTestExecutionListener extends AbstractTestExecutionList } /** - * Process the test instance and make sure that flagged fields for bean - * overriding are processed. Each field get is value updated with the - * overridden bean instance. + * Process the test instance and make sure that fields flagged for bean + * overriding are processed. + *

Each field's value will be updated with the overridden bean instance. */ protected void injectFields(TestContext testContext) { postProcessFields(testContext, (testMetadata, overrideRegistrar) -> overrideRegistrar.inject( @@ -64,9 +62,10 @@ public class BeanOverrideTestExecutionListener extends AbstractTestExecutionList } /** - * Process the test instance and make sure that flagged fields for bean - * overriding are processed. If a fresh instance is required, the field - * is nulled out and then re-injected with the overridden bean instance. + * Process the test instance and make sure that fields flagged for bean + * overriding are processed. + *

If a fresh instance is required, the field is nulled out and then + * re-injected with the overridden bean instance. *

This method does nothing if the * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE} * attribute is not present in the {@code TestContext}. diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java index cc9bdbcf85f..74d0c47a6fd 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java @@ -26,15 +26,15 @@ import org.springframework.core.style.ToStringCreator; import org.springframework.lang.Nullable; /** - * Metadata for Bean Override injection points, also responsible for the - * creation of the overriding instance. + * Metadata for Bean Override injection points, also responsible for creation of + * the overriding instance. * *

WARNING: implementations are used as a cache key and - * must implement proper {@code equals} and {@code hashCode}t methods. + * must implement proper {@code equals()} and {@code hashCode()} methods. * *

Specific implementations of metadata can have state to be used during * override {@linkplain #createOverride(String, BeanDefinition, Object) - * instance creation} — for example, from further parsing of the + * instance creation} — for example, based on further parsing of the * annotation or the annotated field. * * @author Simon Baslé @@ -58,31 +58,32 @@ public abstract class OverrideMetadata { } /** - * Return the bean name to override. + * Get the bean name to override. + *

Defaults to the name of the {@link #getField() field}. */ protected String getBeanName() { return this.field.getName(); } /** - * Return the bean {@link ResolvableType type} to override. + * Get the bean {@linkplain ResolvableType type} to override. */ - public ResolvableType getBeanType() { + public final ResolvableType getBeanType() { return this.beanType; } /** - * Return the annotated {@link Field}. + * Get the annotated {@link Field}. */ - public Field getField() { + public final Field getField() { return this.field; } /** - * Return the {@link BeanOverrideStrategy} for this instance, as a hint on + * Get the {@link BeanOverrideStrategy} for this instance, as a hint on * how and when the override instance should be created. */ - public BeanOverrideStrategy getStrategy() { + public final BeanOverrideStrategy getStrategy() { return this.strategy; } @@ -91,9 +92,9 @@ public abstract class OverrideMetadata { * optionally provided with an existing {@link BeanDefinition} and/or an * original instance, that is a singleton or an early wrapped instance. * @param beanName the name of the bean being overridden - * @param existingBeanDefinition an existing bean definition for that bean - * name, or {@code null} if not relevant - * @param existingBeanInstance an existing instance for that bean name, + * @param existingBeanDefinition an existing bean definition for the supplied + * bean name, or {@code null} if not relevant + * @param existingBeanInstance an existing instance for the supplied bean name * for wrapping purposes, or {@code null} if irrelevant * @return the instance with which to override the bean */