From cf3171dae021e0e43f638574a5e417b8394a828c Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Tue, 4 Jun 2024 18:47:32 +0200 Subject: [PATCH] =?UTF-8?q?Find=20unique=20@=E2=81=A0TestBean=20factory=20?= =?UTF-8?q?methods=20in=20class=20hierarchy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I accidentally introduced a regression in commit d185bb1d97 by no longer checking the number of unique method names found when searching for @⁠TestBean factory methods. This commit reintroduces that check and introduces a proper unit test in TestBeanOverrideProcessorTests. It turns out that we already had an integration test that was intended to check for this scenario; however, that test actually did not test this scenario due to a copy-and-paste error. Thus, this commit also updates TestBeanInheritanceIntegrationTests so that fieldInSupertypeWithPrioritizedFactoryMethodInSubtype() tests what it's supposed to. --- .../convention/TestBeanOverrideProcessor.java | 8 ++--- .../TestBeanInheritanceIntegrationTests.java | 9 ++++-- .../TestBeanOverrideProcessorTests.java | 29 +++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java index a70254b7ee..5e28e57c7a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java @@ -92,16 +92,16 @@ class TestBeanOverrideProcessor implements BeanOverrideProcessor { Set methods = findMethods(clazz, methodFilter); - int methodCount = methods.size(); - Assert.state(methodCount > 0, () -> """ + Assert.state(!methods.isEmpty(), () -> """ Failed to find a static test bean factory method in %s with return type %s \ whose name matches one of the supported candidates %s""".formatted( clazz.getName(), methodReturnType.getName(), supportedNames)); - Assert.state(methodCount == 1, () -> """ + long uniqueMethodNameCount = methods.stream().map(Method::getName).distinct().count(); + Assert.state(uniqueMethodNameCount == 1, () -> """ Found %d competing static test bean factory methods in %s with return type %s \ whose name matches one of the supported candidates %s""".formatted( - methodCount, clazz.getName(), methodReturnType.getName(), supportedNames)); + uniqueMethodNameCount, clazz.getName(), methodReturnType.getName(), supportedNames)); return methods.iterator().next(); } diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanInheritanceIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanInheritanceIntegrationTests.java index 70a73a8fdb..22c3a5c39a 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanInheritanceIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanInheritanceIntegrationTests.java @@ -61,6 +61,11 @@ public class TestBeanInheritanceIntegrationTests { return new FakePojo("someBeanOverride"); } + // Hides otherBeanTestOverride() defined in AbstractTestBeanIntegrationTestCase. + static Pojo otherBeanTestOverride() { + return new FakePojo("otherBean in subclass"); + } + @Test void fieldInSubtypeWithFactoryMethodInSupertype() { assertThat(ctx.getBean("pojo")).as("applicationContext").hasToString("in superclass"); @@ -75,8 +80,8 @@ public class TestBeanInheritanceIntegrationTests { @Test void fieldInSupertypeWithPrioritizedFactoryMethodInSubtype() { - assertThat(ctx.getBean("someBean")).as("applicationContext").hasToString("someBeanOverride"); - assertThat(this.someBean.getValue()).as("injection point").isEqualTo("someBeanOverride"); + assertThat(ctx.getBean("otherBean")).as("applicationContext").hasToString("otherBean in subclass"); + assertThat(super.otherBean.getValue()).as("injection point").isEqualTo("otherBean in subclass"); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java index f6874d5bb8..19e8ff5a67 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java @@ -26,6 +26,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.lang.NonNull; import org.springframework.test.context.bean.override.convention.TestBeanOverrideProcessor.TestBeanOverrideMetadata; import org.springframework.test.context.bean.override.example.ExampleService; +import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -51,6 +52,16 @@ class TestBeanOverrideProcessorTests { assertThat(method.getName()).isEqualTo("example2"); } + @Test + void findTestBeanFactoryMethodFindsLocalMethodWhenSubclassMethodHidesSuperclassMethod() { + Class clazz = SubTestCase.class; + Class returnType = String.class; + + Method method = findTestBeanFactoryMethod(clazz, returnType, "factory"); + + assertThat(method).isEqualTo(ReflectionUtils.findMethod(clazz, "factory")); + } + @Test void findTestBeanFactoryMethodNotFound() { Class clazz = MethodConventionTestCase.class; @@ -174,4 +185,22 @@ class TestBeanOverrideProcessorTests { } } + static class BaseTestCase { + + @TestBean(methodName = "factory") + public String field; + + static String factory() { + return null; + } + } + + static class SubTestCase extends BaseTestCase { + + // Hides factory() in superclass. + static String factory() { + return null; + } + } + }