From 31f8e12adb5e06df05aed25b628d21094a88960b Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Wed, 29 May 2024 14:20:22 +0200 Subject: [PATCH] =?UTF-8?q?Separate=20failure=20and=20success=20scenario?= =?UTF-8?q?=20tests=20for=20@=E2=81=A0TestBean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit also ensures that @⁠Bean methods are declared within @⁠Configuration classes instead of within test classes. See gh-29122 --- .../FailingTestBeanIntegrationTests.java | 229 ++++++++++++++++++ .../convention/TestBeanIntegrationTests.java | 166 +------------ 2 files changed, 235 insertions(+), 160 deletions(-) create mode 100644 spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java 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 new file mode 100644 index 000000000000..eb37a7082955 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/FailingTestBeanIntegrationTests.java @@ -0,0 +1,229 @@ +/* + * 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.junit.platform.engine.TestExecutionResult; +import org.junit.platform.testkit.engine.EngineExecutionResults; +import org.junit.platform.testkit.engine.EngineTestKit; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.aot.DisabledInAotMode; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; + +/** + * {@link TestBean @TestBean} integration tests for failure scenarios. + * + * @since 6.2 + * @see TestBeanIntegrationTests + */ +public class FailingTestBeanIntegrationTests { + + @Test + void testBeanFailingNoFieldNameBean() { + EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// + .selectors(selectClass(NoOriginalBeanTestCase.class))// + .execute(); + + assertThat(results.allEvents().failed().stream()).hasSize(1).first() + .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) + .getThrowable()).get(THROWABLE) + .cause() + .isInstanceOf(IllegalStateException.class) + .hasMessage("Unable to override bean 'noOriginalBean'; " + + "there is no bean definition to replace with that name of type java.lang.String")); + } + + @Test + void testBeanFailingNoExplicitNameBean() { + EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// + .selectors(selectClass(BeanDefinitionToOverrideNotPresentTestCase.class))// + .execute(); + + assertThat(results.allEvents().failed().stream()).hasSize(1).first() + .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) + .getThrowable()).get(THROWABLE) + .cause() + .isInstanceOf(IllegalStateException.class) + .hasMessage("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 = ExplicitTestOverrideMethodNotPresentTestCase.class; + EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// + .selectors(selectClass(testClass))// + .execute(); + + assertThat(results.allEvents().failed().stream()).hasSize(1).first() + .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) + .getThrowable()).get(THROWABLE) + .rootCause().isInstanceOf(IllegalStateException.class) + .hasMessage("Failed to find a static test bean factory method in %s " + + "with return type java.lang.String whose name matches one of the " + + "supported candidates [notPresent]", testClass.getName())); + } + + @Test + void testBeanFailingNoExplicitMethod() { + Class testClass = ImplicitTestOverrideMethodNotPresentTestCase.class; + EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// + .selectors(selectClass(testClass))// + .execute(); + + assertThat(results.allEvents().failed().stream()).hasSize(1).first() + .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) + .getThrowable()).get(THROWABLE) + .rootCause().isInstanceOf(IllegalStateException.class) + .hasMessage("Failed to find a static test bean factory method in %s " + + "with return type java.lang.String whose name matches one of the " + + "supported candidates [fieldTestOverride]", testClass.getName())); + } + + @Test + void testBeanFailingBeanOfWrongType() { + EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// + .selectors(selectClass(BeanTypeMismatchTestCase.class))// + .execute(); + + assertThat(results.allEvents().failed().stream()).hasSize(1).first() + .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) + .getThrowable()).get(THROWABLE) + .rootCause().isInstanceOf(IllegalStateException.class) + .hasMessage("Unable to override bean 'notString'; there is no bean definition to replace with " + + "that name of type java.lang.String")); + } + + @Configuration + static class Config { + + @Bean("field") + String bean1() { + return "prod"; + } + + @Bean("nestedField") + String bean2() { + return "nestedProd"; + } + + @Bean("methodRenamed1") + String bean3() { + return "Prod"; + } + + @Bean("methodRenamed2") + String bean4() { + return "NestedProd"; + } + } + + @SpringJUnitConfig + @DisabledInAotMode + static class NoOriginalBeanTestCase { + + @TestBean(name = "noOriginalBean") + String noOriginalBean; + + @Test + void ignored() { + fail("should fail earlier"); + } + + static String noOriginalBeanTestOverride() { + return "should be ignored"; + } + + } + + @SpringJUnitConfig + @DisabledInAotMode + static class BeanDefinitionToOverrideNotPresentTestCase { + + @TestBean(name = "notPresent") + String field; + + @Test + void ignored() { + fail("should fail earlier"); + } + + static String notPresentTestOverride() { + return "should be ignored"; + } + } + + @SpringJUnitConfig + @DisabledInAotMode + static class ExplicitTestOverrideMethodNotPresentTestCase { + + @TestBean(methodName = "notPresent") + String field; + + @Test + void ignored() { + fail("should fail earlier"); + } + } + + @SpringJUnitConfig + @DisabledInAotMode + static class ImplicitTestOverrideMethodNotPresentTestCase { + + @TestBean //expects fieldTestOverride method + String field; + + @Test + void ignored() { + fail("should fail earlier"); + } + } + + @SpringJUnitConfig + @DisabledInAotMode + static class BeanTypeMismatchTestCase { + + @TestBean(name = "notString") + String field; + + @Test + void ignored() { + fail("should fail earlier"); + } + + static String fieldTestOverride() { + 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/TestBeanIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanIntegrationTests.java index a69ab86ee965..87b8a74cdc66 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanIntegrationTests.java @@ -19,9 +19,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.testkit.engine.EngineExecutionResults; -import org.junit.platform.testkit.engine.EngineTestKit; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -29,10 +26,13 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +/** + * {@link TestBean @TestBean} integration tests for success scenarios. + * + * @since 6.2 + * @see FailingTestBeanIntegrationTests + */ @SpringJUnitConfig public class TestBeanIntegrationTests { @@ -80,81 +80,6 @@ void fieldWithMethodNameHasOverride(ApplicationContext ctx) { assertThat(this.methodRenamed1).as("injection point").isEqualTo("fieldOverride"); } - @Test - void testBeanFailingNoFieldNameBean() { - EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(Failing1.class))// - .execute(); - - assertThat(results.allEvents().failed().stream()).hasSize(1).first() - .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) - .getThrowable()).get(THROWABLE) - .cause() - .isInstanceOf(IllegalStateException.class) - .hasMessage("Unable to override bean 'noOriginalBean'; " + - "there is no bean definition to replace with that name of type java.lang.String")); - } - - @Test - void testBeanFailingNoExplicitNameBean() { - EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(Failing2.class))// - .execute(); - - assertThat(results.allEvents().failed().stream()).hasSize(1).first() - .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) - .getThrowable()).get(THROWABLE) - .cause() - .isInstanceOf(IllegalStateException.class) - .hasMessage("Unable to override bean 'notPresent'; " + - "there is no bean definition to replace with that name of type java.lang.String")); - } - - @Test - void testBeanFailingNoImplicitMethod() { - EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(Failing3.class))// - .execute(); - - assertThat(results.allEvents().failed().stream()).hasSize(1).first() - .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) - .getThrowable()).get(THROWABLE) - .rootCause().isInstanceOf(IllegalStateException.class) - .hasMessage("Failed to find a static test bean factory method in " + - "org.springframework.test.context.bean.override.convention.TestBeanIntegrationTests$Failing3 " + - "with return type java.lang.String whose name matches one of the " + - "supported candidates [notPresent]")); - } - - @Test - void testBeanFailingNoExplicitMethod() { - EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(Failing4.class))// - .execute(); - - assertThat(results.allEvents().failed().stream()).hasSize(1).first() - .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) - .getThrowable()).get(THROWABLE) - .rootCause().isInstanceOf(IllegalStateException.class) - .hasMessage("Failed to find a static test bean factory method in " + - "org.springframework.test.context.bean.override.convention.TestBeanIntegrationTests$Failing4 " + - "with return type java.lang.String whose name matches one of the " + - "supported candidates [fieldTestOverride]")); - } - - @Test - void testBeanFailingBeanOfWrongType() { - EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(Failing5.class))// - .execute(); - - assertThat(results.allEvents().failed().stream()).hasSize(1).first() - .satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class) - .getThrowable()).get(THROWABLE) - .rootCause().isInstanceOf(IllegalStateException.class) - .hasMessage("Unable to override bean 'notString'; there is no bean definition to replace with " + - "that name of type java.lang.String")); - } @Nested @DisplayName("With @TestBean on enclosing class") @@ -177,7 +102,6 @@ void fieldWithMethodNameHasOverride(ApplicationContext ctx) { assertThat(ctx.getBean("methodRenamed2")).as("applicationContext").isEqualTo("nestedFieldOverride"); assertThat(TestBeanIntegrationTests.this.methodRenamed2).isEqualTo("nestedFieldOverride"); } - } @Nested @@ -192,7 +116,6 @@ void fieldHasOverride(ApplicationContext ctx) { assertThat(ctx.getBean("nestedField")).as("applicationContext").isEqualTo("nestedFieldOverride"); assertThat(this.nestedField2).isEqualTo("nestedFieldOverride"); } - } @@ -220,81 +143,4 @@ String bean4() { } } - @SpringJUnitConfig - static class Failing1 { - - @TestBean(name = "noOriginalBean") - String noOriginalBean; - - @Test - void ignored() { - fail("should fail earlier"); - } - - static String noOriginalBeanTestOverride() { - return "should be ignored"; - } - - } - - @SpringJUnitConfig - static class Failing2 { - - @TestBean(name = "notPresent") - String field; - - @Test - void ignored() { - fail("should fail earlier"); - } - - static String notPresentTestOverride() { - return "should be ignored"; - } - } - - @SpringJUnitConfig - static class Failing3 { - - @TestBean(methodName = "notPresent") - String field; - - @Test - void ignored() { - fail("should fail earlier"); - } - } - - @SpringJUnitConfig - static class Failing4 { - - @TestBean //expects fieldTestOverride method - String field; - - @Test - void ignored() { - fail("should fail earlier"); - } - } - - @SpringJUnitConfig - static class Failing5 { - - @Bean("notString") - StringBuilder bean1() { - return new StringBuilder("not a String"); - } - - @TestBean(name = "notString") - String field; - - @Test - void ignored() { - fail("should fail earlier"); - } - - static String fieldTestOverride() { - return "should be ignored"; - } - } }