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 7e117c4b1824..1fba7c75a132 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 @@ -18,7 +18,6 @@ import java.lang.reflect.Field; import java.util.List; -import java.util.function.BiConsumer; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener; @@ -26,10 +25,12 @@ import org.springframework.util.ReflectionUtils; /** - * {@code TestExecutionListener} that enables Bean Override support in tests, - * injecting overridden beans in appropriate fields of the test instance. + * {@code TestExecutionListener} that enables {@link BeanOverride @BeanOverride} + * support in tests, by injecting overridden beans in appropriate fields of the + * test instance. * * @author Simon Baslé + * @author Sam Brannen * @since 6.2 */ public class BeanOverrideTestExecutionListener extends AbstractTestExecutionListener { @@ -42,64 +43,57 @@ public int getOrder() { return LOWEST_PRECEDENCE - 50; } - @Override - public void prepareTestInstance(TestContext testContext) throws Exception { - injectFields(testContext); - } - - @Override - public void beforeTestMethod(TestContext testContext) throws Exception { - reinjectFieldsIfNecessary(testContext); - } - /** - * Process the test instance and make sure that fields flagged for bean - * overriding are injected with the overridden bean instance. + * Inject each {@link BeanOverride @BeanOverride} field in the + * {@linkplain Object test instance} of the supplied {@linkplain TestContext + * test context} with a corresponding bean override instance. */ - protected void injectFields(TestContext testContext) { - postProcessFields(testContext, (testMetadata, registrar) -> - registrar.inject(testMetadata.testInstance, testMetadata.overrideMetadata)); + @Override + public void prepareTestInstance(TestContext testContext) throws Exception { + injectFields(testContext, false); } /** - * Process the test instance and make sure that fields flagged for bean - * overriding are injected with the overridden bean instance, if necessary. - *

If a fresh instance is required, the field is nulled out and then - * re-injected with the overridden bean instance. + * Re-inject each {@link BeanOverride @BeanOverride} field in the + * {@linkplain Object test instance} of the supplied {@linkplain TestContext + * test context} with a corresponding bean override instance. *

This method does nothing if the - * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE} - * attribute is not present in the {@code TestContext} with a value of {@link Boolean#TRUE}. + * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE + * REINJECT_DEPENDENCIES_ATTRIBUTE} attribute is not present in the + * {@code TestContext} with a value of {@link Boolean#TRUE}. */ - protected void reinjectFieldsIfNecessary(TestContext testContext) throws Exception { - if (Boolean.TRUE.equals( - testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) { - - postProcessFields(testContext, (testMetadata, registrar) -> { - Object testInstance = testMetadata.testInstance; - Field field = testMetadata.overrideMetadata.getField(); - ReflectionUtils.makeAccessible(field); - ReflectionUtils.setField(field, testInstance, null); - registrar.inject(testInstance, testMetadata.overrideMetadata); - }); + @Override + public void beforeTestMethod(TestContext testContext) throws Exception { + Object reinjectDependenciesAttribute = testContext.getAttribute( + DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE); + if (Boolean.TRUE.equals(reinjectDependenciesAttribute)) { + injectFields(testContext, true); } } - private void postProcessFields(TestContext testContext, BiConsumer consumer) { - - Class testClass = testContext.getTestClass(); - Object testInstance = testContext.getTestInstance(); - - List metadataForFields = OverrideMetadata.forTestClass(testClass); - if (!metadataForFields.isEmpty()) { + /** + * Inject each {@link BeanOverride @BeanOverride} field in the test instance with + * a corresponding bean override instance. + *

If the {@code reinjectFields} flag is {@code true} (which indicates that + * a fresh instance is required), the field is nulled out before injecting + * the overridden bean instance. + */ + private static void injectFields(TestContext testContext, boolean reinjectFields) { + List overrideMetadataList = OverrideMetadata.forTestClass(testContext.getTestClass()); + if (!overrideMetadataList.isEmpty()) { + Object testInstance = testContext.getTestInstance(); BeanOverrideRegistrar registrar = testContext.getApplicationContext() .getBean(BeanOverrideContextCustomizer.REGISTRAR_BEAN_NAME, BeanOverrideRegistrar.class); - for (OverrideMetadata metadata : metadataForFields) { - consumer.accept(new TestContextOverrideMetadata(testInstance, metadata), registrar); + + for (OverrideMetadata overrideMetadata : overrideMetadataList) { + if (reinjectFields) { + Field field = overrideMetadata.getField(); + ReflectionUtils.makeAccessible(field); + ReflectionUtils.setField(field, testInstance, null); + } + registrar.inject(testInstance, overrideMetadata); } } } - private record TestContextOverrideMetadata(Object testInstance, OverrideMetadata overrideMetadata) {} - }