diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessor.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessor.java new file mode 100644 index 00000000000..b75649c1645 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessor.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2022 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.boot.test.autoconfigure; + +import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; +import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.test.context.ApplicationContextFailureProcessor; + +/** + * An {@link ApplicationContextFailureProcessor} that prints the + * {@link ConditionEvaluationReport} when the context cannot be prepared. + * + * @author Phillip Webb + * @author Scott Frederick + * @since 3.0.0 + */ +public class ConditionReportApplicationContextFailureProcessor implements ApplicationContextFailureProcessor { + + @Override + public void processLoadFailure(ApplicationContext context, Throwable exception) { + if (context instanceof ConfigurableApplicationContext configurableContext) { + ConditionEvaluationReport report = ConditionEvaluationReport.get(configurableContext.getBeanFactory()); + System.err.println(new ConditionEvaluationReportMessage(report)); + } + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListener.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListener.java index 79da370fdbc..9b3085a0fbd 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListener.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListener.java @@ -16,25 +16,24 @@ package org.springframework.boot.test.autoconfigure; -import java.util.ArrayList; -import java.util.List; - import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage; -import org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.test.context.ApplicationContextFailureProcessor; import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestExecutionListener; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; /** - * Alternative {@link DependencyInjectionTestExecutionListener} prints the - * {@link ConditionEvaluationReport} when the context cannot be prepared. + * Since 3.0.0 this class has been replaced by + * {@link ConditionReportApplicationContextFailureProcessor} and is not used internally. * * @author Phillip Webb * @since 1.4.1 + * @deprecated since 3.0.0 for removal in 3.2.0 in favor of + * {@link ApplicationContextFailureProcessor} */ +@Deprecated(since = "3.0.0", forRemoval = true) public class SpringBootDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener { @Override @@ -61,19 +60,4 @@ public class SpringBootDependencyInjectionTestExecutionListener extends Dependen } } - static class PostProcessor implements DefaultTestExecutionListenersPostProcessor { - - @Override - public List postProcessDefaultTestExecutionListeners( - List listeners) { - List updated = new ArrayList<>(); - for (TestExecutionListener listener : listeners) { - updated.add((listener instanceof DependencyInjectionTestExecutionListener) - ? new SpringBootDependencyInjectionTestExecutionListener() : listener); - } - return updated; - } - - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index 5a0cf67166a..64fb54f860d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -1,7 +1,3 @@ -# DefaultTestExecutionListenersPostProcessors -org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor=\ -org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener$PostProcessor - # Spring Test ContextCustomizerFactories org.springframework.test.context.ContextCustomizerFactory=\ org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory,\ @@ -17,3 +13,6 @@ org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerRese org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener,\ org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener,\ org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener + +org.springframework.test.context.ApplicationContextFailureProcessor=\ +org.springframework.boot.test.autoconfigure.ConditionReportApplicationContextFailureProcessor \ No newline at end of file diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessorTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessorTests.java new file mode 100644 index 00000000000..69a7b01e570 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ConditionReportApplicationContextFailureProcessorTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2022 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.boot.test.autoconfigure; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ConditionReportApplicationContextFailureProcessor}. + * + * @author Phillip Webb + * @author Scott Frederick + */ +@ExtendWith(OutputCaptureExtension.class) +class ConditionReportApplicationContextFailureProcessorTests { + + @Test + void loadFailureShouldPrintReport(CapturedOutput output) throws Exception { + SpringApplication application = new SpringApplication(TestConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + ConfigurableApplicationContext applicationContext = application.run(); + ConditionReportApplicationContextFailureProcessor processor = new ConditionReportApplicationContextFailureProcessor(); + processor.processLoadFailure(applicationContext, new IllegalStateException()); + assertThat(output).contains("CONDITIONS EVALUATION REPORT").contains("Positive matches") + .contains("Negative matches"); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(JacksonAutoConfiguration.class) + static class TestConfig { + + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerPostConstructIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerPostConstructIntegrationTests.java deleted file mode 100644 index d7cc431e906..00000000000 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerPostConstructIntegrationTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2022 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.boot.test.autoconfigure; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import jakarta.annotation.PostConstruct; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for {@link SpringBootDependencyInjectionTestExecutionListener}. - * - * @author Phillip Webb - */ -@SpringBootTest -class SpringBootDependencyInjectionTestExecutionListenerPostConstructIntegrationTests { - - private List calls = new ArrayList<>(); - - @PostConstruct - void postConstruct() { - StringWriter writer = new StringWriter(); - new RuntimeException().printStackTrace(new PrintWriter(writer)); - this.calls.add(writer.toString()); - } - - @Test - void postConstructShouldBeInvokedOnlyOnce() { - // gh-6874 - assertThat(this.calls).hasSize(1); - } - - @Configuration(proxyBeanMethods = false) - static class Config { - - } - -} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerTests.java deleted file mode 100644 index e5052427823..00000000000 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/SpringBootDependencyInjectionTestExecutionListenerTests.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012-2022 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.boot.test.autoconfigure; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link SpringBootDependencyInjectionTestExecutionListener}. - * - * @author Phillip Webb - */ -@ExtendWith(OutputCaptureExtension.class) -class SpringBootDependencyInjectionTestExecutionListenerTests { - - private SpringBootDependencyInjectionTestExecutionListener reportListener = new SpringBootDependencyInjectionTestExecutionListener(); - - @Test - void orderShouldBeSameAsDependencyInjectionTestExecutionListener() { - Ordered injectionListener = new DependencyInjectionTestExecutionListener(); - assertThat(this.reportListener.getOrder()).isEqualTo(injectionListener.getOrder()); - } - - @Test - @SuppressWarnings({ "unchecked", "rawtypes" }) - void prepareFailingTestInstanceShouldPrintReport(CapturedOutput output) throws Exception { - TestContext testContext = mock(TestContext.class); - given(testContext.getTestClass()).willReturn((Class) Config.class); - given(testContext.getTestInstance()).willThrow(new IllegalStateException()); - SpringApplication application = new SpringApplication(Config.class); - application.setWebApplicationType(WebApplicationType.NONE); - ConfigurableApplicationContext applicationContext = application.run(); - given(testContext.getApplicationContext()).willReturn(applicationContext); - try { - this.reportListener.prepareTestInstance(testContext); - } - catch (IllegalStateException ex) { - // Expected - } - assertThat(output).contains("CONDITIONS EVALUATION REPORT").contains("Positive matches") - .contains("Negative matches"); - } - - @Test - @SuppressWarnings({ "unchecked", "rawtypes" }) - void originalFailureIsThrownWhenReportGenerationFails() { - TestContext testContext = mock(TestContext.class); - given(testContext.getTestClass()).willReturn((Class) Config.class); - IllegalStateException originalFailure = new IllegalStateException(); - given(testContext.getTestInstance()).willThrow(originalFailure); - SpringApplication application = new SpringApplication(Config.class); - application.setWebApplicationType(WebApplicationType.NONE); - given(testContext.getApplicationContext()).willThrow(new RuntimeException()); - assertThatIllegalStateException().isThrownBy(() -> this.reportListener.prepareTestInstance(testContext)) - .isEqualTo(originalFailure); - } - - @Configuration(proxyBeanMethods = false) - @ImportAutoConfiguration(JacksonAutoConfiguration.class) - static class Config { - - } - -} diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/DefaultTestExecutionListenersPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/DefaultTestExecutionListenersPostProcessor.java index 4b67232419a..5ba6125a05a 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/DefaultTestExecutionListenersPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/DefaultTestExecutionListenersPostProcessor.java @@ -18,19 +18,19 @@ package org.springframework.boot.test.context; import java.util.List; +import org.springframework.test.context.ApplicationContextFailureProcessor; import org.springframework.test.context.TestExecutionListener; /** - * Callback interface trigger from {@link SpringBootTestContextBootstrapper} that can be - * used to post-process the list of default {@link TestExecutionListener - * TestExecutionListeners} to be used by a test. Can be used to add or remove existing - * listeners. + * Since 3.0.0 this class is not used internally. * * @author Phillip Webb * @since 1.4.1 - * @see SpringBootTest + * @deprecated since 3.0.0 removal in 3.2.0 in favor of + * {@link ApplicationContextFailureProcessor} */ @FunctionalInterface +@Deprecated(since = "3.0.0", forRemoval = true) public interface DefaultTestExecutionListenersPostProcessor { /** diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java index 7a852eef815..82155ea7e5c 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java @@ -38,7 +38,6 @@ import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.env.Environment; -import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.ContextCustomizer; @@ -48,7 +47,6 @@ import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.TestContext; import org.springframework.test.context.TestContextAnnotationUtils; import org.springframework.test.context.TestContextBootstrapper; -import org.springframework.test.context.TestExecutionListener; import org.springframework.test.context.aot.AotTestAttributes; import org.springframework.test.context.support.DefaultTestContextBootstrapper; import org.springframework.test.context.support.TestPropertySourceUtils; @@ -122,17 +120,6 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr return context; } - @Override - protected List getDefaultTestExecutionListeners() { - List listeners = new ArrayList<>(super.getDefaultTestExecutionListeners()); - List postProcessors = SpringFactoriesLoader - .loadFactories(DefaultTestExecutionListenersPostProcessor.class, getClass().getClassLoader()); - for (DefaultTestExecutionListenersPostProcessor postProcessor : postProcessors) { - listeners = postProcessor.postProcessDefaultTestExecutionListeners(listeners); - } - return listeners; - } - @Override protected ContextLoader resolveContextLoader(Class testClass, List configAttributesList) { diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperIntegrationTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperIntegrationTests.java index 9f663e68776..a8233d05056 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperIntegrationTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperIntegrationTests.java @@ -45,8 +45,6 @@ class SpringBootTestContextBootstrapperIntegrationTests { @Autowired private SpringBootTestContextBootstrapperExampleConfig config; - boolean defaultTestExecutionListenersPostProcessorCalled = false; - @Test void findConfigAutomatically() { assertThat(this.config).isNotNull(); @@ -62,11 +60,6 @@ class SpringBootTestContextBootstrapperIntegrationTests { assertThat(this.context.getBean(ExampleBean.class)).isNotNull(); } - @Test - void defaultTestExecutionListenersPostProcessorShouldBeCalled() { - assertThat(this.defaultTestExecutionListenersPostProcessorCalled).isTrue(); - } - @TestConfiguration(proxyBeanMethods = false) static class TestConfig { diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/TestDefaultTestExecutionListenersPostProcessor.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/TestDefaultTestExecutionListenersPostProcessor.java deleted file mode 100644 index 170c9f63e22..00000000000 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/TestDefaultTestExecutionListenersPostProcessor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012-2022 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.boot.test.context.bootstrap; - -import java.util.List; - -import org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestExecutionListener; -import org.springframework.test.context.support.AbstractTestExecutionListener; - -/** - * Test {@link DefaultTestExecutionListenersPostProcessor}. - * - * @author Phillip Webb - */ -public class TestDefaultTestExecutionListenersPostProcessor implements DefaultTestExecutionListenersPostProcessor { - - @Override - public List postProcessDefaultTestExecutionListeners(List listeners) { - listeners.add(new ExampleTestExecutionListener()); - return listeners; - } - - static class ExampleTestExecutionListener extends AbstractTestExecutionListener { - - @Override - public void prepareTestInstance(TestContext testContext) throws Exception { - Object testInstance = testContext.getTestInstance(); - if (testInstance instanceof SpringBootTestContextBootstrapperIntegrationTests test) { - test.defaultTestExecutionListenersPostProcessorCalled = true; - } - } - - } - -} diff --git a/spring-boot-project/spring-boot-test/src/test/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test/src/test/resources/META-INF/spring.factories deleted file mode 100644 index 5eecd4c7e9e..00000000000 --- a/spring-boot-project/spring-boot-test/src/test/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor=\ -org.springframework.boot.test.context.bootstrap.TestDefaultTestExecutionListenersPostProcessor