Polish Bean Override support in the TestContext framework

This commit is contained in:
Sam Brannen
2024-03-10 16:05:55 +01:00
parent 4c246b7c96
commit 6f5d3a4b12
21 changed files with 333 additions and 292 deletions

View File

@@ -19,7 +19,6 @@ package org.springframework.test.bean.override;
import java.util.Map;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanWrapper;
@@ -47,18 +46,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNoException;
/**
* Test for {@link BeanOverrideBeanPostProcessor}.
* Tests for for {@link BeanOverrideBeanPostProcessor}.
*
* @author Simon Baslé
*/
class BeanOverrideBeanPostProcessorTests {
BeanOverrideParser parser;
private final BeanOverrideParser parser = new BeanOverrideParser();
@BeforeEach
void initParser() {
this.parser = new BeanOverrideParser();
}
@Test
void canReplaceExistingBeanDefinitions() {
@@ -83,8 +78,9 @@ class BeanOverrideBeanPostProcessorTests {
context.register(ReplaceBeans.class);
//note we don't register any original bean here
assertThatIllegalStateException().isThrownBy(context::refresh).withMessage("Unable to override test bean, " +
"expected a bean definition to replace with name 'explicit'");
assertThatIllegalStateException()
.isThrownBy(context::refresh)
.withMessage("Unable to override test bean; expected a bean definition to replace with name 'explicit'");
}
@Test
@@ -125,7 +121,9 @@ class BeanOverrideBeanPostProcessorTests {
factoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, SomeInterface.class);
context.registerBeanDefinition("beanToBeOverridden", factoryBeanDefinition);
context.register(OverriddenFactoryBean.class);
context.refresh();
assertThat(context.getBean("beanToBeOverridden")).isSameAs(OVERRIDE);
}
@@ -139,11 +137,12 @@ class BeanOverrideBeanPostProcessorTests {
factoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, objectType);
context.registerBeanDefinition("beanToBeOverridden", factoryBeanDefinition);
context.register(OverriddenFactoryBean.class);
context.refresh();
assertThat(context.getBean("beanToBeOverridden")).isSameAs(OVERRIDE);
}
@Test
void postProcessorShouldNotTriggerEarlyInitialization() {
this.parser.parse(EagerInitBean.class);
@@ -192,6 +191,7 @@ class BeanOverrideBeanPostProcessorTests {
.matches(Predicate.not(BeanDefinition::isPrototype), "!isPrototype");
}
/*
Classes to parse and register with the bean post processor
-----
@@ -228,7 +228,6 @@ class BeanOverrideBeanPostProcessorTests {
static ExampleService useThis() {
return OVERRIDE_SERVICE;
}
}
@Configuration(proxyBeanMethods = false)
@@ -245,7 +244,6 @@ class BeanOverrideBeanPostProcessorTests {
TestFactoryBean testFactoryBean() {
return new TestFactoryBean();
}
}
static class EagerInitBean {
@@ -256,7 +254,6 @@ class BeanOverrideBeanPostProcessorTests {
static ExampleService useThis() {
return OVERRIDE_SERVICE;
}
}
static class SingletonBean {
@@ -268,7 +265,6 @@ class BeanOverrideBeanPostProcessorTests {
static String useThis() {
return "USED THIS";
}
}
static class TestFactoryBean implements FactoryBean<Object> {
@@ -287,7 +283,6 @@ class BeanOverrideBeanPostProcessorTests {
public boolean isSingleton() {
return true;
}
}
static class FactoryBeanRegisteringPostProcessor implements BeanFactoryPostProcessor, Ordered {
@@ -302,7 +297,6 @@ class BeanOverrideBeanPostProcessorTests {
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
static class EarlyBeanInitializationDetector implements BeanFactoryPostProcessor {
@@ -314,15 +308,12 @@ class BeanOverrideBeanPostProcessorTests {
"factoryBeanInstanceCache");
Assert.isTrue(cache.isEmpty(), "Early initialization of factory bean triggered.");
}
}
interface SomeInterface {
}
static class SomeImplementation implements SomeInterface {
}
}

View File

@@ -16,58 +16,63 @@
package org.springframework.test.bean.override;
import java.lang.reflect.Field;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.bean.override.example.ExampleBeanOverrideAnnotation;
import org.springframework.test.bean.override.example.TestBeanOverrideMetaAnnotation;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
import static org.springframework.test.bean.override.example.ExampleBeanOverrideProcessor.DUPLICATE_TRIGGER;
/**
* Unit tests for {@link BeanOverrideParser}.
*
* @since 6.2
*/
class BeanOverrideParserTests {
private final BeanOverrideParser parser = new BeanOverrideParser();
@Test
void findsOnField() {
BeanOverrideParser parser = new BeanOverrideParser();
parser.parse(OnFieldConf.class);
parser.parse(SingleAnnotationOnField.class);
assertThat(parser.getOverrideMetadata()).hasSize(1)
.first()
.extracting(om -> ((ExampleBeanOverrideAnnotation) om.overrideAnnotation()).value())
.isEqualTo("onField");
assertThat(parser.getOverrideMetadata())
.map(om -> ((ExampleBeanOverrideAnnotation) om.overrideAnnotation()).value())
.containsExactly("onField");
}
@Test
void allowMultipleProcessorsOnDifferentElements() {
BeanOverrideParser parser = new BeanOverrideParser();
parser.parse(MultipleFieldsWithOnFieldConf.class);
void allowsMultipleProcessorsOnDifferentElements() {
parser.parse(AnnotationsOnMultipleFields.class);
assertThat(parser.getOverrideMetadata())
.hasSize(2)
.map(om -> ((ExampleBeanOverrideAnnotation) om.overrideAnnotation()).value())
.containsOnly("onField1", "onField2");
.containsExactlyInAnyOrder("onField1", "onField2");
}
@Test
void rejectsMultipleAnnotationsOnSameElement() {
BeanOverrideParser parser = new BeanOverrideParser();
assertThatRuntimeException().isThrownBy(() -> parser.parse(MultipleOnFieldConf.class))
.withMessage("Multiple bean override annotations found on annotated field <" +
String.class.getName() + " " + MultipleOnFieldConf.class.getName() + ".message>");
Field field = ReflectionUtils.findField(MultipleAnnotationsOnField.class, "message");
assertThatRuntimeException()
.isThrownBy(() -> parser.parse(MultipleAnnotationsOnField.class))
.withMessage("Multiple @BeanOverride annotations found on field: " + field);
}
@Test
void detectsDuplicateMetadata() {
BeanOverrideParser parser = new BeanOverrideParser();
assertThatRuntimeException().isThrownBy(() -> parser.parse(DuplicateConf.class))
.withMessage("Duplicate test overrideMetadata {DUPLICATE_TRIGGER}");
assertThatRuntimeException()
.isThrownBy(() -> parser.parse(DuplicateConf.class))
.withMessage("Duplicate test OverrideMetadata: {DUPLICATE_TRIGGER}");
}
@Configuration
static class OnFieldConf {
static class SingleAnnotationOnField {
@ExampleBeanOverrideAnnotation("onField")
String message;
@@ -75,11 +80,9 @@ class BeanOverrideParserTests {
static String onField() {
return "OK";
}
}
@Configuration
static class MultipleOnFieldConf {
static class MultipleAnnotationsOnField {
@ExampleBeanOverrideAnnotation("foo")
@TestBeanOverrideMetaAnnotation
@@ -88,11 +91,10 @@ class BeanOverrideParserTests {
static String foo() {
return "foo";
}
}
@Configuration
static class MultipleFieldsWithOnFieldConf {
static class AnnotationsOnMultipleFields {
@ExampleBeanOverrideAnnotation("onField1")
String message;
@@ -108,7 +110,6 @@ class BeanOverrideParserTests {
}
}
@Configuration
static class DuplicateConf {
@ExampleBeanOverrideAnnotation(DUPLICATE_TRIGGER)
@@ -116,7 +117,6 @@ class BeanOverrideParserTests {
@ExampleBeanOverrideAnnotation(DUPLICATE_TRIGGER)
String message2;
}
}

View File

@@ -25,15 +25,13 @@ import org.springframework.test.bean.override.OverrideMetadata;
public class ExampleBeanOverrideProcessor implements BeanOverrideProcessor {
public ExampleBeanOverrideProcessor() {
}
private static final TestOverrideMetadata CONSTANT = new TestOverrideMetadata() {
@Override
public String toString() {
return "{DUPLICATE_TRIGGER}";
}
};
public static final String DUPLICATE_TRIGGER = "CONSTANT";
@Override
@@ -46,4 +44,5 @@ public class ExampleBeanOverrideProcessor implements BeanOverrideProcessor {
}
return new TestOverrideMetadata(field, annotation, typeToOverride);
}
}