From 3f2d9c372da4bf9d889e5c9e0f5766975dac7b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 12 Jun 2024 11:03:14 +0200 Subject: [PATCH] Migrate "Failing" test cases to regular tests This commit replaces the use of EngineTestKit to test scenarios where bean override could not process the test class. There is no need to run an actual test for this as: 1. Regular integration tests are already validating that adding the annotation triggers the processing as part of executing the test. 2. The entry point is a ContextCustomizer that can easily be invoked in a regular test. As part of harmonizing this, AbstractTestBeanIntegrationTestCase can be nested, and BeanOverrideTestSuite serve no purpose. The tests can be executed in an IDE without any special setup. --- ...eanOverrideContextCustomizerTestUtils.java | 17 ++ .../bean/override/BeanOverrideTestSuite.java | 56 ----- .../AbstractTestBeanIntegrationTestCase.java | 99 --------- ...FailingTestBeanByTypeIntegrationTests.java | 121 ----------- ...ngTestBeanInheritanceIntegrationTests.java | 80 -------- .../FailingTestBeanIntegrationTests.java | 179 ---------------- ...stBeanForByNameLookupIntegrationTests.java | 1 - ...stBeanForByTypeLookupIntegrationTests.java | 1 - ...estBeanForInheritanceIntegrationTests.java | 90 +++++++- .../override/convention/TestBeanTests.java | 193 ++++++++++++++++++ ...lingMockitoBeanByTypeIntegrationTests.java | 85 -------- ...gMockitoSpyBeanByTypeIntegrationTests.java | 113 ---------- ...FailingMockitoSpyBeanIntegrationTests.java | 86 -------- ...toBeanForByTypeLookupIntegrationTests.java | 1 - .../mockito/MockitoMockBeanTests.java | 54 +++++ ...pyBeanForByTypeLookupIntegrationTests.java | 1 - .../override/mockito/MockitoSpyBeanTests.java | 85 ++++++++ .../context/junit/EngineTestKitUtils.java | 67 ------ 18 files changed, 433 insertions(+), 896 deletions(-) delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideTestSuite.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/AbstractTestBeanIntegrationTestCase.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanByTypeIntegrationTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanInheritanceIntegrationTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoBeanByTypeIntegrationTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanByTypeIntegrationTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanIntegrationTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoMockBeanTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanTests.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/junit/EngineTestKitUtils.java diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizerTestUtils.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizerTestUtils.java index e3aada2b8a8c..72d1c9999054 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizerTestUtils.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizerTestUtils.java @@ -18,8 +18,12 @@ import java.util.Collections; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.lang.Nullable; import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.MergedContextConfiguration; + +import static org.mockito.Mockito.mock; /** * Test utilities for {@link BeanOverrideContextCustomizer} that are public so @@ -44,4 +48,17 @@ public static ContextCustomizer createContextCustomizer(Class testClass) { return factory.createContextCustomizer(testClass, Collections.emptyList()); } + /** + * Configure the given {@linkplain ConfigurableApplicationContext application + * context} for the given {@code testClass}. + * @param testClass the test to process + * @param context the context to configure + */ + public static void configureApplicationContext(Class testClass, ConfigurableApplicationContext context) { + ContextCustomizer contextCustomizer = createContextCustomizer(testClass); + if (contextCustomizer != null) { + contextCustomizer.customizeContext(context, mock(MergedContextConfiguration.class)); + } + } + } diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideTestSuite.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideTestSuite.java deleted file mode 100644 index 4d6049f6f9bd..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideTestSuite.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override; - -import org.junit.jupiter.api.ClassOrderer; -import org.junit.platform.suite.api.ConfigurationParameter; -import org.junit.platform.suite.api.ExcludeTags; -import org.junit.platform.suite.api.IncludeClassNamePatterns; -import org.junit.platform.suite.api.IncludeEngines; -import org.junit.platform.suite.api.SelectPackages; -import org.junit.platform.suite.api.Suite; - -/** - * JUnit Platform based test suite for tests that involve bean override support - * in the Spring TestContext Framework. - * - *

This suite is only intended to be used manually within an IDE. - * - *

Logging Configuration

- * - *

In order for our log4j2 configuration to be used in an IDE, you must - * set the following system property before running any tests — for - * example, in Run Configurations in Eclipse. - * - *

- * -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
- * 
- * - * @author Sam Brannen - * @since 6.2 - */ -@Suite -@IncludeEngines("junit-jupiter") -@SelectPackages("org.springframework.test.context.bean.override") -@IncludeClassNamePatterns(".*Tests$") -@ExcludeTags("failing-test-case") -@ConfigurationParameter( - key = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME, - value = "org.junit.jupiter.api.ClassOrderer$ClassName" -) -public class BeanOverrideTestSuite { -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/AbstractTestBeanIntegrationTestCase.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/AbstractTestBeanIntegrationTestCase.java deleted file mode 100644 index 7a5407363a93..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/AbstractTestBeanIntegrationTestCase.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.convention; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -@SpringJUnitConfig -abstract class AbstractTestBeanIntegrationTestCase { - - @TestBean(name = "someBean") - Pojo someBean; - - @TestBean(name = "otherBean") - Pojo otherBean; - - @TestBean(name = "thirdBean") - Pojo anotherBean; - - static Pojo otherBean() { - return new FakePojo("otherBean in superclass"); - } - - static Pojo thirdBean() { - return new FakePojo("third in superclass"); - } - - static Pojo commonBeanOverride() { - return new FakePojo("in superclass"); - } - - interface Pojo { - - default String getValue() { - return "Prod"; - } - } - - static class ProdPojo implements Pojo { } - - static class FakePojo implements Pojo { - final String value; - - protected FakePojo(String value) { - this.value = value; - } - - @Override - public String getValue() { - return this.value; - } - - @Override - public String toString() { - return getValue(); - } - } - - @Configuration - static class Config { - - @Bean - Pojo someBean() { - return new ProdPojo(); - } - @Bean - Pojo otherBean() { - return new ProdPojo(); - } - @Bean - Pojo thirdBean() { - return new ProdPojo(); - } - @Bean - Pojo pojo() { - return new ProdPojo(); - } - @Bean - Pojo pojo2() { - return new ProdPojo(); - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanByTypeIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanByTypeIntegrationTests.java deleted file mode 100644 index 71b00087c794..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanByTypeIntegrationTests.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.convention; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.bean.override.example.ExampleService; -import org.springframework.test.context.bean.override.example.RealExampleService; -import org.springframework.test.context.junit.EngineTestKitUtils; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.assertj.core.api.Assertions.fail; -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; - -/** - * {@link TestBean @TestBean} "by type" integration tests for failure scenarios. - * - * @author Simon Baslé - * @author Sam Brannen - * @since 6.2 - */ -class FailingTestBeanByTypeIntegrationTests { - - @Test - void zeroCandidates() { - Class testClass = NoMatchingBeansTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to override bean: no bean definitions of type \ - %s (as required by annotated field '%s.example')""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName()))))); - } - - @Test - void tooManyCandidates() { - Class testClass = TooManyBeansTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to select a bean definition to override: found 2 bean definitions \ - of type %s (as required by annotated field '%s.example'): %s""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName(), List.of("bean1", "bean2")))))); - } - - - @SpringJUnitConfig - static class NoMatchingBeansTestCase { - - @TestBean - ExampleService example; - - @Test - void test() { - } - - static ExampleService example() { - return fail("unexpected override"); - } - - @Configuration - static class Config { - } - } - - - @SpringJUnitConfig - static class TooManyBeansTestCase { - - @TestBean - ExampleService example; - - @Test - void test() { - } - - static ExampleService example() { - return fail("unexpected override"); - } - - @Configuration - static class Config { - - @Bean - ExampleService bean1() { - return new RealExampleService("1 Hello"); - } - - @Bean - ExampleService bean2() { - return new RealExampleService("2 Hello"); - } - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanInheritanceIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanInheritanceIntegrationTests.java deleted file mode 100644 index 77cb966eb6b4..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanInheritanceIntegrationTests.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.convention; - -import org.junit.jupiter.api.Test; - -import org.springframework.test.context.bean.override.convention.AbstractTestBeanIntegrationTestCase.Pojo; -import org.springframework.test.context.junit.EngineTestKitUtils; - -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; - -/** - * {@link TestBean @TestBean} inheritance integration tests for failure scenarios. - * - * @author Simon Baslé - * @author Sam Brannen - * @since 6.2 - */ -class FailingTestBeanInheritanceIntegrationTests { - - @Test - void failsIfFieldInSupertypeButNoMethod() { - Class testClass = FieldInSupertypeButNoMethodTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - instanceOf(IllegalStateException.class), - message("No static method found named someBean() in %s with return type %s" - .formatted(FieldInSupertypeButNoMethodTestCase.class.getName(), Pojo.class.getName())))); - } - - @Test - void failsIfMethod1InSupertypeAndMethod2InType() { - Class testClass = Method1InSupertypeAndMethod2InTypeTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - instanceOf(IllegalStateException.class), - message("Found 2 competing static methods named anotherBean() or thirdBean() in %s with return type %s" - .formatted(Method1InSupertypeAndMethod2InTypeTestCase.class.getName(), Pojo.class.getName())))); - } - - - static class FieldInSupertypeButNoMethodTestCase extends AbstractTestBeanIntegrationTestCase { - - @Test - void test() { - } - } - - static class Method1InSupertypeAndMethod2InTypeTestCase extends AbstractTestBeanIntegrationTestCase { - - static Pojo someBean() { - return new FakePojo("ignored"); - } - - static Pojo anotherBean() { - return new FakePojo("sub2"); - } - - @Test - void test() { - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java deleted file mode 100644 index c07115eb706a..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.convention; - -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit.EngineTestKitUtils; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.assertj.core.api.Assertions.fail; -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; -import static org.springframework.test.context.junit.EngineTestKitUtils.rootCause; - -/** - * {@link TestBean @TestBean} integration tests for failure scenarios. - * - * @author Simon Baslé - * @author Sam Brannen - * @since 6.2 - */ -class FailingTestBeanIntegrationTests { - - @Test - void testBeanFailingNoFieldNameBean() { - Class testClass = NoOriginalBeanTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to override bean 'noOriginalBean': there is no bean definition \ - to replace with that name of type java.lang.String""")))); - } - - @Test - void testBeanFailingNoExplicitNameBean() { - Class testClass = BeanDefinitionToOverrideNotPresentTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to override bean 'notPresent': there is no bean definition \ - to replace with that name of type java.lang.String""")))); - } - - @Test - void testBeanFailingNoImplicitMethod() { - Class testClass = ExplicitOverrideMethodNotPresentTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - instanceOf(IllegalStateException.class), - message("No static method found named notPresent() in %s with return type %s" - .formatted(testClass.getName(), String.class.getName())))); - } - - @Test - void testBeanFailingNoExplicitMethod() { - Class testClass = ImplicitOverrideMethodNotPresentTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure(instanceOf(IllegalStateException.class), - message("No static method found named field() in %s with return type %s" - .formatted(testClass.getName(), String.class.getName())))); - } - - @Test - void testBeanFailingBeanOfWrongType() { - Class testClass = BeanTypeMismatchTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - rootCause( - instanceOf(IllegalStateException.class), - message(""" - Unable to override bean 'notString': there is no bean definition to replace \ - with that name of type java.lang.String""")))); - } - - - @SpringJUnitConfig - static class NoOriginalBeanTestCase { - - @TestBean(name = "noOriginalBean") - String noOriginalBean; - - @Test - void test() { - fail("should fail earlier"); - } - - static String noOriginalBean() { - return "should be ignored"; - } - } - - @SpringJUnitConfig - static class BeanDefinitionToOverrideNotPresentTestCase { - - @TestBean(name = "notPresent") - String field; - - @Test - void test() { - fail("should fail earlier"); - } - - static String notPresent() { - return "should be ignored"; - } - } - - @SpringJUnitConfig - static class ExplicitOverrideMethodNotPresentTestCase { - - @TestBean(methodName = "notPresent") - String field; - - @Test - void test() { - fail("should fail earlier"); - } - } - - @SpringJUnitConfig - static class ImplicitOverrideMethodNotPresentTestCase { - - @TestBean // expects field method - String field; - - @Test - void test() { - fail("should fail earlier"); - } - } - - @SpringJUnitConfig - static class BeanTypeMismatchTestCase { - - @TestBean(name = "notString") - String field; - - @Test - void test() { - fail("should fail earlier"); - } - - static String field() { - return "should be ignored"; - } - - @Configuration - static class Config { - - @Bean("notString") - StringBuilder bean1() { - return new StringBuilder("not a String"); - } - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByNameLookupIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByNameLookupIntegrationTests.java index 425df5f0fe57..41aa6b307b6f 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByNameLookupIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByNameLookupIntegrationTests.java @@ -33,7 +33,6 @@ * @author Simon Baslé * @author Sam Brannen * @since 6.2 - * @see FailingTestBeanIntegrationTests */ @SpringJUnitConfig public class TestBeanForByNameLookupIntegrationTests { diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByTypeLookupIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByTypeLookupIntegrationTests.java index a1eaf07316ed..668a1d57c44d 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByTypeLookupIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByTypeLookupIntegrationTests.java @@ -35,7 +35,6 @@ * @author Simon Baslé * @author Sam Brannen * @since 6.2 - * @see FailingTestBeanByTypeIntegrationTests */ @SpringJUnitConfig class TestBeanForByTypeLookupIntegrationTests { diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForInheritanceIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForInheritanceIntegrationTests.java index e00843dbda34..0389dad6b053 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForInheritanceIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForInheritanceIntegrationTests.java @@ -22,8 +22,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.test.context.bean.override.convention.AbstractTestBeanIntegrationTestCase.FakePojo; -import org.springframework.test.context.bean.override.convention.AbstractTestBeanIntegrationTestCase.Pojo; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.bean.override.convention.TestBeanForInheritanceIntegrationTests.AbstractTestBeanIntegrationTestCase.FakePojo; +import org.springframework.test.context.bean.override.convention.TestBeanForInheritanceIntegrationTests.AbstractTestBeanIntegrationTestCase.Pojo; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -36,7 +39,6 @@ * @author Simon Baslé * @author Sam Brannen * @since 6.2 - * @see FailingTestBeanInheritanceIntegrationTests */ class TestBeanForInheritanceIntegrationTests { @@ -44,10 +46,89 @@ static Pojo enclosingClassBeanOverride() { return new FakePojo("in enclosing test class"); } + @SpringJUnitConfig + abstract static class AbstractTestBeanIntegrationTestCase { + + @TestBean(name = "someBean") + Pojo someBean; + + @TestBean(name = "otherBean") + Pojo otherBean; + + @TestBean(name = "thirdBean") + Pojo anotherBean; + + static Pojo otherBean() { + return new FakePojo("otherBean in superclass"); + } + + static Pojo thirdBean() { + return new FakePojo("third in superclass"); + } + + static Pojo commonBeanOverride() { + return new FakePojo("in superclass"); + } + + interface Pojo { + + default String getValue() { + return "Prod"; + } + } + + static class ProdPojo implements Pojo { } + + static class FakePojo implements Pojo { + final String value; + + protected FakePojo(String value) { + this.value = value; + } + + @Override + public String getValue() { + return this.value; + } + + @Override + public String toString() { + return getValue(); + } + } + + @Configuration + static class Config { + + @Bean + Pojo someBean() { + return new ProdPojo(); + } + @Bean + Pojo otherBean() { + return new ProdPojo(); + } + @Bean + Pojo thirdBean() { + return new ProdPojo(); + } + @Bean + Pojo pojo() { + return new ProdPojo(); + } + @Bean + Pojo pojo2() { + return new ProdPojo(); + } + } + + } + @Nested @DisplayName("Nested, concrete inherited tests with correct @TestBean setup") class NestedConcreteTestBeanIntegrationTests extends AbstractTestBeanIntegrationTestCase { + @Autowired ApplicationContext ctx; @@ -60,7 +141,6 @@ class NestedConcreteTestBeanIntegrationTests extends AbstractTestBeanIntegration static Pojo someBean() { return new FakePojo("someBeanOverride"); } - // Hides otherBean() defined in AbstractTestBeanIntegrationTestCase. static Pojo otherBean() { return new FakePojo("otherBean in subclass"); @@ -83,12 +163,10 @@ void fieldInSupertypeWithPrioritizedFactoryMethodInSubtype() { assertThat(ctx.getBean("otherBean")).as("applicationContext").hasToString("otherBean in subclass"); assertThat(super.otherBean.getValue()).as("injection point").isEqualTo("otherBean in subclass"); } - @Test void fieldInNestedClassWithFactoryMethodInEnclosingClass() { assertThat(ctx.getBean("pojo2")).as("applicationContext").hasToString("in enclosing test class"); assertThat(this.pojo2.getValue()).as("injection point").isEqualTo("in enclosing test class"); } } - } diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanTests.java new file mode 100644 index 000000000000..03c2909d192c --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanTests.java @@ -0,0 +1,193 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.bean.override.convention; + +import java.util.List; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.bean.override.BeanOverrideContextCustomizerTestUtils; + +/** + * Tests for {@link TestBean}. + * + * @author Stephane Nicoll + */ +public class TestBeanTests { + + @Test + void contextCustomizerCannotBeCreatedWithNoSuchBeanName() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("anotherBean", String.class, () -> "example"); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(FailureByNameLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to override bean 'beanToOverride': there is no bean definition \ + to replace with that name of type java.lang.String"""); + } + + @Test + void contextCustomizerCannotBeCreatedWithNoSuchBeanType() { + GenericApplicationContext context = new GenericApplicationContext(); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(FailureByTypeLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to override bean: no bean definitions of \ + type %s (as required by annotated field '%s.example')""".formatted( + String.class.getName(), FailureByTypeLookup.class.getSimpleName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithTooManyBeansOfThatType() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("bean1", String.class, () -> "example1"); + context.registerBean("bean2", String.class, () -> "example2"); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(FailureByTypeLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to select a bean definition to override: found 2 bean definitions \ + of type %s (as required by annotated field '%s.example'): %s""".formatted( + String.class.getName(), FailureByTypeLookup.class.getSimpleName(), List.of("bean1", "bean2"))); + } + + @Test + void contextCustomizerCannotBeCreatedWithBeanOfWrongType() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("beanToOverride", Integer.class, () -> 42); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(FailureByNameLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to override bean 'beanToOverride': there is no bean definition \ + to replace with that name of type %s""".formatted( + String.class.getName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithMissingOverrideMethod() { + GenericApplicationContext context = new GenericApplicationContext(); + Assertions.assertThatIllegalStateException() + .isThrownBy(() -> BeanOverrideContextCustomizerTestUtils.configureApplicationContext( + FailureMissingDefaultOverrideMethod.class, context)) + .withMessage("No static method found named example() or beanToOverride() in %s with return type %s" + .formatted(FailureMissingDefaultOverrideMethod.class.getName(), String.class.getName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithMissingExplicitOverrideMethod() { + GenericApplicationContext context = new GenericApplicationContext(); + Assertions.assertThatIllegalStateException() + .isThrownBy(() -> BeanOverrideContextCustomizerTestUtils.configureApplicationContext( + FailureMissingExplicitOverrideMethod.class, context)) + .withMessage("No static method found named createExample() in %s with return type %s" + .formatted(FailureMissingExplicitOverrideMethod.class.getName(), String.class.getName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithFieldInParentAndMissingOverrideMethod() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("beanToOverride", String.class, () -> "example"); + Assertions.assertThatIllegalStateException() + .isThrownBy(() -> BeanOverrideContextCustomizerTestUtils.configureApplicationContext( + FailureOverrideInParentWithoutFactoryMethod.class, context)) + .withMessage("No static method found named beanToOverride() in %s with return type %s" + .formatted(FailureOverrideInParentWithoutFactoryMethod.class.getName(), String.class.getName())); + } + + @Test + void contextCustomizerCannotBeCreatedWitCompetingOverrideMethods() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("bean", String.class, () -> "example"); + Assertions.assertThatIllegalStateException() + .isThrownBy(() -> BeanOverrideContextCustomizerTestUtils.configureApplicationContext( + FailureCompetingOverrideMethods.class, context)) + .withMessage("Found 2 competing static methods named example() or beanToOverride() in %s with return type %s" + .formatted(FailureCompetingOverrideMethods.class.getName(), String.class.getName())); + } + + static class FailureByTypeLookup { + + @TestBean + private String example; + + private static String example() { + throw new IllegalStateException("Should not be called"); + } + } + + static class FailureByNameLookup { + + @TestBean(name = "beanToOverride") + private String example; + + private static String example() { + throw new IllegalStateException("Should not be called"); + } + } + + static class FailureMissingDefaultOverrideMethod { + + @TestBean(name = "beanToOverride") + private String example; + + // Expected static String example() { ... } + // or static String beanToOverride() { ... } + + } + + static class FailureMissingExplicitOverrideMethod { + + @TestBean(methodName = "createExample") + private String example; + + // Expected static String createExample() { ... } + + } + + abstract static class AbstractByNameLookup { + + @TestBean(methodName = "beanToOverride") + protected String beanToOverride; + + } + + static class FailureOverrideInParentWithoutFactoryMethod extends AbstractByNameLookup { + + // No beanToOverride() method + + } + + abstract static class AbstractCompetingMethods { + + @TestBean(name = "beanToOverride") + protected String example; + + static String example() { + throw new IllegalStateException("Should not be called"); + } + } + + static class FailureCompetingOverrideMethods extends AbstractCompetingMethods { + + static String beanToOverride() { + throw new IllegalStateException("Should not be called"); + } + + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoBeanByTypeIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoBeanByTypeIntegrationTests.java deleted file mode 100644 index e3b2ed6fad55..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoBeanByTypeIntegrationTests.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.mockito; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.bean.override.example.ExampleService; -import org.springframework.test.context.bean.override.example.RealExampleService; -import org.springframework.test.context.junit.EngineTestKitUtils; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; - -/** - * {@link MockitoBean @MockitoBean} "by type" integration tests for failure scenarios. - * - * @author Simon Baslé - * @author Sam Brannen - * @since 6.2 - */ -class FailingMockitoBeanByTypeIntegrationTests { - - @Test - void tooManyCandidates() { - Class testClass = TooManyCandidatesTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to select a bean definition to override: found 2 bean definitions \ - of type %s (as required by annotated field '%s.example'): %s""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName(), List.of("bean1", "bean2")))))); - } - - - @SpringJUnitConfig - static class TooManyCandidatesTestCase { - - @MockitoBean - ExampleService example; - - @Test - void test() { - assertThat(example).isNotNull(); - } - - @Configuration - static class Config { - - @Bean - ExampleService bean1() { - return new RealExampleService("1 Hello"); - } - - @Bean - ExampleService bean2() { - return new RealExampleService("2 Hello"); - } - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanByTypeIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanByTypeIntegrationTests.java deleted file mode 100644 index c51172c736e6..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanByTypeIntegrationTests.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.mockito; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.bean.override.example.ExampleService; -import org.springframework.test.context.bean.override.example.RealExampleService; -import org.springframework.test.context.junit.EngineTestKitUtils; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; - -/** - * {@link MockitoSpyBean @MockitoSpyBean} "by type" integration tests for failure scenarios. - * - * @author Sam Brannen - * @since 6.2 - */ -class FailingMockitoSpyBeanByTypeIntegrationTests { - - @Test - void zeroCandidates() { - Class testClass = ZeroCandidatesTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to select a bean to override by wrapping: found 0 bean instances of \ - type %s (as required by annotated field '%s.example')""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName()))))); - } - - @Test - void tooManyCandidates() { - Class testClass = TooManyCandidatesTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause( - instanceOf(IllegalStateException.class), - message(""" - Unable to select a bean to override by wrapping: found 2 bean instances of \ - type %s (as required by annotated field '%s.example'): %s""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName(), List.of("bean1", "bean2")))))); - } - - - @SpringJUnitConfig - static class ZeroCandidatesTestCase { - - @MockitoSpyBean - ExampleService example; - - @Test - void test() { - assertThat(example).isNotNull(); - } - - @Configuration - static class Config { - } - } - - @SpringJUnitConfig - static class TooManyCandidatesTestCase { - - @MockitoSpyBean - ExampleService example; - - @Test - void test() { - assertThat(example).isNotNull(); - } - - @Configuration - static class Config { - - @Bean - ExampleService bean1() { - return new RealExampleService("1 Hello"); - } - - @Bean - ExampleService bean2() { - return new RealExampleService("2 Hello"); - } - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanIntegrationTests.java deleted file mode 100644 index 3f550a96d1a3..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/FailingMockitoSpyBeanIntegrationTests.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.bean.override.mockito; - -import org.junit.jupiter.api.Test; - -import org.springframework.test.context.bean.override.example.ExampleService; -import org.springframework.test.context.junit.EngineTestKitUtils; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; -import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; - -/** - * {@link MockitoSpyBean @MockitoSpyBean} integration tests for failure scenarios. - * - * @author Simon Baslé - * @author Sam Brannen - * @since 6.2 - */ -class FailingMockitoSpyBeanIntegrationTests { - - @Test - void failWhenBeanNotPresentByType() { - Class testClass = BeanNotPresentByTypeTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause(instanceOf(IllegalStateException.class), - message(""" - Unable to select a bean to override by wrapping: found 0 bean instances \ - of type %s (as required by annotated field '%s.notPresent')""" - .formatted(ExampleService.class.getName(), testClass.getSimpleName()))))); - } - - @Test - void failWhenBeanNotPresentByExplicitName() { - Class testClass = BeanNotPresentByExplicitNameTestCase.class; - EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1, - finishedWithFailure( - cause(instanceOf(IllegalStateException.class), - message(""" - Unable to override bean 'notPresentAtAll' by wrapping: \ - there is no existing bean instance with that name of type %s""" - .formatted(ExampleService.class.getName()))))); - } - - - @SpringJUnitConfig - static class BeanNotPresentByTypeTestCase { - - @MockitoSpyBean - ExampleService notPresent; - - @Test - void test() { - } - } - - @SpringJUnitConfig - static class BeanNotPresentByExplicitNameTestCase { - - @MockitoSpyBean(name = "notPresentAtAll") - ExampleService field; - - @Test - void test() { - } - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByTypeLookupIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByTypeLookupIntegrationTests.java index 1538baa523fe..5d326c20fef1 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByTypeLookupIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByTypeLookupIntegrationTests.java @@ -44,7 +44,6 @@ * @author Simon Baslé * @author Sam Brannen * @since 6.2 - * @see FailingMockitoBeanByTypeIntegrationTests */ @SpringJUnitConfig public class MockitoBeanForByTypeLookupIntegrationTests { diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoMockBeanTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoMockBeanTests.java new file mode 100644 index 000000000000..9cd42b32e84d --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoMockBeanTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.bean.override.mockito; + +import java.util.List; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.bean.override.BeanOverrideContextCustomizerTestUtils; + +/** + * Tests for {@link MockitoBean}. + * + * @author Stephane Nicoll + */ +class MockitoMockBeanTests { + + @Test + void contextCustomizerCannotBeCreatedWithTooManyCandidates() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("bean1", String.class, () -> "example1"); + context.registerBean("bean2", String.class, () -> "example2"); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(ByTypeSingleLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to select a bean definition to override: found 2 bean definitions \ + of type %s (as required by annotated field '%s.example'): %s""".formatted( + String.class.getName(), ByTypeSingleLookup.class.getSimpleName(), List.of("bean1", "bean2"))); + } + + + static class ByTypeSingleLookup { + + @MockitoBean + String example; + + } +} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForByTypeLookupIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForByTypeLookupIntegrationTests.java index 3a06b611962d..1bda6283dd8b 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForByTypeLookupIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForByTypeLookupIntegrationTests.java @@ -41,7 +41,6 @@ * @author Simon Baslé * @author Sam Brannen * @since 6.2 - * @see FailingMockitoSpyBeanByTypeIntegrationTests */ @SpringJUnitConfig public class MockitoSpyBeanForByTypeLookupIntegrationTests { diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanTests.java new file mode 100644 index 000000000000..6d6a7077f948 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.bean.override.mockito; + +import java.util.List; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.bean.override.BeanOverrideContextCustomizerTestUtils; + +/** + * Tests for {@link MockitoSpyBean}. + * + * @author Stephane Nicoll + */ +class MockitoSpyBeanTests { + + @Test + void contextCustomizerCannotBeCreatedWithNoSuchBeanName() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("present", String.class, () -> "example"); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(ByNameSingleLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to override bean 'beanToSpy' by wrapping: \ + there is no existing bean instance with that name of type %s""".formatted( + String.class.getName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithNoSuchBeanType() { + GenericApplicationContext context = new GenericApplicationContext(); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(ByTypeSingleLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to select a bean to override by wrapping: found 0 bean instances of \ + type %s (as required by annotated field '%s.example')""".formatted( + String.class.getName(), ByTypeSingleLookup.class.getSimpleName())); + } + + @Test + void contextCustomizerCannotBeCreatedWithTooManyBeansOfThatType() { + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBean("bean1", String.class, () -> "example1"); + context.registerBean("bean2", String.class, () -> "example2"); + BeanOverrideContextCustomizerTestUtils.configureApplicationContext(ByTypeSingleLookup.class, context); + Assertions.assertThatIllegalStateException().isThrownBy(context::refresh) + .withMessage(""" + Unable to select a bean to override by wrapping: found 2 bean instances \ + of type %s (as required by annotated field '%s.example'): %s""".formatted( + String.class.getName(), ByTypeSingleLookup.class.getSimpleName(), List.of("bean1", "bean2"))); + } + + + static class ByTypeSingleLookup { + + @MockitoSpyBean + String example; + + } + + static class ByNameSingleLookup { + + @MockitoSpyBean(name = "beanToSpy") + String example; + + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/EngineTestKitUtils.java b/spring-test/src/test/java/org/springframework/test/context/junit/EngineTestKitUtils.java deleted file mode 100644 index 1342ebe495aa..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/junit/EngineTestKitUtils.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.junit; - -import java.util.Arrays; -import java.util.List; - -import org.assertj.core.api.Assertions; -import org.assertj.core.api.Condition; -import org.junit.platform.testkit.engine.EngineTestKit; -import org.junit.platform.testkit.engine.Events; - -import org.springframework.core.NestedExceptionUtils; - -import static java.util.stream.Collectors.toList; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; - -/** - * Utilities for tests that use JUnit's {@link EngineTestKit}. - * - * @author Sam Brannen - * @since 6.2 - */ -public class EngineTestKitUtils { - - public static Events executeTestsForClass(Class testClass) { - return EngineTestKit.engine("junit-jupiter") - .selectors(selectClass(testClass)) - .execute() - .allEvents(); - } - - /** - * Create a new {@link Condition} that matches if and only if a - * {@link Throwable}'s root {@linkplain Throwable#getCause() cause} matches - * all supplied conditions. - */ - @SafeVarargs - @SuppressWarnings("varargs") - public static Condition rootCause(Condition... conditions) { - List> list = Arrays.stream(conditions) - .map(EngineTestKitUtils::rootCause) - .collect(toList()); - - return Assertions.allOf(list); - } - - private static Condition rootCause(Condition condition) { - return new Condition<>(throwable -> condition.matches(NestedExceptionUtils.getRootCause(throwable)), - "throwable root cause matches %s", condition); - } - -}