diff --git a/spring-test/src/main/java/org/springframework/test/context/ApplicationContextFailureProcessor.java b/spring-test/src/main/java/org/springframework/test/context/ApplicationContextFailureProcessor.java new file mode 100644 index 00000000000..a947cbbfddd --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/ApplicationContextFailureProcessor.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-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.test.context; + +import org.springframework.context.ApplicationContext; + +/** + * Strategy for components that process failures related to application contexts + * within the Spring TestContext Framework. + * + * @author Sam Brannen + * @since 6.0 + * @see ContextLoadException + */ +public interface ApplicationContextFailureProcessor { + + /** + * Invoked when a failure was encountered while attempting to load an + * {@link ApplicationContext}. + *
Implementations of this method must not throw any exceptions. Consequently, + * any exception thrown by an implementation of this method will be ignored. + * @param context the application context that did not load successfully + * @param exception the exception caught while loading the application context + */ + void processLoadFailure(ApplicationContext context, Throwable exception); + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java b/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java index efd6dca1780..d7086c3ae80 100644 --- a/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java +++ b/spring-test/src/main/java/org/springframework/test/context/CacheAwareContextLoaderDelegate.java @@ -75,6 +75,7 @@ public interface CacheAwareContextLoaderDelegate { * the application context * @see #isContextLoaded * @see #closeContext + * @see #setContextFailureProcessor */ ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration); @@ -100,4 +101,18 @@ public interface CacheAwareContextLoaderDelegate { */ void closeContext(MergedContextConfiguration mergedContextConfiguration, @Nullable HierarchyMode hierarchyMode); + /** + * Set the {@link ApplicationContextFailureProcessor} to use. + *
The default implementation ignores the supplied processor. + *
Concrete implementations should override this method to store a reference + * to the supplied processor and use it to process {@link ContextLoadException + * ContextLoadExceptions} thrown from context loaders in + * {@link #loadContext(MergedContextConfiguration)}. + * @param contextFailureProcessor the context failure processor to use + * @since 6.0 + */ + default void setContextFailureProcessor(ApplicationContextFailureProcessor contextFailureProcessor) { + // no-op + } + } diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextLoadException.java b/spring-test/src/main/java/org/springframework/test/context/ContextLoadException.java new file mode 100644 index 00000000000..723d8ebb3c8 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/context/ContextLoadException.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-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.test.context; + +import org.springframework.context.ApplicationContext; + +/** + * Exception thrown when an error occurs while a {@link SmartContextLoader} + * attempts to load an {@link ApplicationContext}. + * + *
This exception provides access to the {@linkplain #getApplicationContext() + * application context} that failed to load as well as the {@linkplain #getCause() + * exception} caught while attempting to load that context. + * + * @author Sam Brannen + * @since 6.0 + * @see SmartContextLoader#loadContext(MergedContextConfiguration) + */ +@SuppressWarnings("serial") +public class ContextLoadException extends Exception { + + private final ApplicationContext applicationContext; + + + /** + * Create a new {@code ContextLoadException} for the supplied + * {@link ApplicationContext} and {@link Exception}. + * @param applicationContext the application context that failed to load + * @param cause the exception caught while attempting to load that context + */ + public ContextLoadException(ApplicationContext applicationContext, Exception cause) { + super(cause); + this.applicationContext = applicationContext; + } + + + /** + * Get the {@code ApplicationContext} that failed to load. + *
Clients must not retain a long-lived reference to the context returned + * from this method. + */ + public ApplicationContext getApplicationContext() { + return this.applicationContext; + } + +} diff --git a/spring-test/src/main/java/org/springframework/test/context/SmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/SmartContextLoader.java index 09091083cf8..3461a7b1355 100644 --- a/spring-test/src/main/java/org/springframework/test/context/SmartContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/SmartContextLoader.java @@ -126,10 +126,23 @@ public interface SmartContextLoader extends ContextLoader { * closed on JVM shutdown. This allows for freeing of external resources held * by beans within the context — for example, temporary files. * + *
As of Spring Framework 6.0, any exception thrown while attempting to + * load an {@code ApplicationContext} should be wrapped in a + * {@link ContextLoadException}. Concrete implementations should therefore + * contain a try-catch block similar to the following. + *
+ * ApplicationContext context = // create context
+ * try {
+ * // configure and refresh context
+ * }
+ * catch (Exception ex) {
+ * throw new ContextLoadException(context, ex);
+ * }
+ *
* @param mergedConfig the merged context configuration to use to load the
* application context
* @return a new application context
- * @throws Exception if context loading failed
+ * @throws ContextLoadException if context loading failed
* @see #processContextConfiguration(ContextConfigurationAttributes)
* @see #loadContextForAotProcessing(MergedContextConfiguration)
* @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java
index 6d9a53e1bb3..25d64980732 100644
--- a/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java
@@ -19,6 +19,7 @@ package org.springframework.test.context.aot;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.context.ContextLoadException;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.SmartContextLoader;
@@ -52,10 +53,22 @@ public interface AotContextLoader extends SmartContextLoader {
* {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
* register a JVM shutdown hook} for it. Otherwise, this method should implement
* behavior identical to {@code loadContext(MergedContextConfiguration)}.
+ * Any exception thrown while attempting to load an {@code ApplicationContext} + * should be wrapped in a {@link ContextLoadException}. Concrete implementations + * should therefore contain a try-catch block similar to the following. + *
+ * GenericApplicationContext context = // create context
+ * try {
+ * // configure context
+ * }
+ * catch (Exception ex) {
+ * throw new ContextLoadException(context, ex);
+ * }
+ *
* @param mergedConfig the merged context configuration to use to load the
* application context
* @return a new {@code GenericApplicationContext}
- * @throws Exception if context loading failed
+ * @throws ContextLoadException if context loading failed
* @see #loadContextForAotRuntime(MergedContextConfiguration, ApplicationContextInitializer)
*/
ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception;
@@ -67,12 +80,24 @@ public interface AotContextLoader extends SmartContextLoader {
* This method must instantiate, initialize, and * {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh() * refresh} the {@code ApplicationContext}. + *
Any exception thrown while attempting to load an {@code ApplicationContext} + * should be wrapped in a {@link ContextLoadException}. Concrete implementations + * should therefore contain a try-catch block similar to the following. + *
+ * GenericApplicationContext context = // create context
+ * try {
+ * // configure and refresh context
+ * }
+ * catch (Exception ex) {
+ * throw new ContextLoadException(context, ex);
+ * }
+ *
* @param mergedConfig the merged context configuration to use to load the
* application context
* @param initializer the {@code ApplicationContextInitializer} that should
* be applied to the context in order to recreate bean definitions
* @return a new {@code GenericApplicationContext}
- * @throws Exception if context loading failed
+ * @throws ContextLoadException if context loading failed
* @see #loadContextForAotProcessing(MergedContextConfiguration)
*/
ApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig,
diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java
index 8b81e544d3d..fac0cfc6df2 100644
--- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java
+++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java
@@ -39,6 +39,7 @@ import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.log.LogMessage;
import org.springframework.javapoet.ClassName;
import org.springframework.test.context.BootstrapUtils;
+import org.springframework.test.context.ContextLoadException;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.SmartContextLoader;
@@ -217,9 +218,10 @@ public class TestContextAotGenerator {
}
}
catch (Exception ex) {
+ Throwable cause = (ex instanceof ContextLoadException cle ? cle.getCause() : ex);
throw new TestContextAotException(
"Failed to load ApplicationContext for AOT processing for test class [%s]"
- .formatted(testClass.getName()), ex);
+ .formatted(testClass.getName()), cause);
}
}
throw new TestContextAotException("""
diff --git a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java
index 6566ed4dfda..3a357dc62cb 100644
--- a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java
+++ b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java
@@ -26,7 +26,9 @@ import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.log.LogMessage;
import org.springframework.lang.Nullable;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
+import org.springframework.test.context.ApplicationContextFailureProcessor;
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
+import org.springframework.test.context.ContextLoadException;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.SmartContextLoader;
@@ -59,6 +61,9 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
private final ContextCache contextCache;
+ @Nullable
+ private ApplicationContextFailureProcessor contextFailureProcessor;
+
/**
* Construct a new {@code DefaultCacheAwareContextLoaderDelegate} using
@@ -110,8 +115,23 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
this.contextCache.put(mergedContextConfiguration, context);
}
catch (Exception ex) {
+ Throwable cause = ex;
+ if (ex instanceof ContextLoadException cle) {
+ cause = cle.getCause();
+ if (this.contextFailureProcessor != null) {
+ try {
+ this.contextFailureProcessor.processLoadFailure(cle.getApplicationContext(), cause);
+ }
+ catch (Throwable throwable) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Ignoring exception thrown from ApplicationContextFailureProcessor [%s]: %s"
+ .formatted(this.contextFailureProcessor, throwable));
+ }
+ }
+ }
+ }
throw new IllegalStateException(
- "Failed to load ApplicationContext for " + mergedContextConfiguration, ex);
+ "Failed to load ApplicationContext for " + mergedContextConfiguration, cause);
}
}
else {
@@ -134,6 +154,12 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
}
}
+ @Override
+ public void setContextFailureProcessor(ApplicationContextFailureProcessor contextFailureProcessor) {
+ this.contextFailureProcessor = contextFailureProcessor;
+ }
+
+
/**
* Get the {@link ContextCache} used by this context loader delegate.
*/
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java
index 48c68ae013c..950d7a6c0fd 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java
@@ -28,6 +28,7 @@ import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.test.context.ContextLoadException;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.aot.AotContextLoader;
import org.springframework.util.Assert;
@@ -159,13 +160,18 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
validateMergedContextConfiguration(mergedConfig);
GenericApplicationContext context = createContext();
- prepareContext(context);
- prepareContext(context, mergedConfig);
- initializer.initialize(context);
- customizeContext(context);
- customizeContext(context, mergedConfig);
- context.refresh();
- return context;
+ try {
+ prepareContext(context);
+ prepareContext(context, mergedConfig);
+ initializer.initialize(context);
+ customizeContext(context);
+ customizeContext(context, mergedConfig);
+ context.refresh();
+ return context;
+ }
+ catch (Exception ex) {
+ throw new ContextLoadException(context, ex);
+ }
}
/**
@@ -189,25 +195,30 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
validateMergedContextConfiguration(mergedConfig);
GenericApplicationContext context = createContext();
- ApplicationContext parent = mergedConfig.getParentApplicationContext();
- if (parent != null) {
- context.setParent(parent);
+ try {
+ ApplicationContext parent = mergedConfig.getParentApplicationContext();
+ if (parent != null) {
+ context.setParent(parent);
+ }
+
+ prepareContext(context);
+ prepareContext(context, mergedConfig);
+ customizeBeanFactory(context.getDefaultListableBeanFactory());
+ loadBeanDefinitions(context, mergedConfig);
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
+ customizeContext(context);
+ customizeContext(context, mergedConfig);
+
+ if (!forAotProcessing) {
+ context.refresh();
+ context.registerShutdownHook();
+ }
+
+ return context;
}
-
- prepareContext(context);
- prepareContext(context, mergedConfig);
- customizeBeanFactory(context.getDefaultListableBeanFactory());
- loadBeanDefinitions(context, mergedConfig);
- AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- customizeContext(context);
- customizeContext(context, mergedConfig);
-
- if (!forAotProcessing) {
- context.refresh();
- context.registerShutdownHook();
+ catch (Exception ex) {
+ throw new ContextLoadException(context, ex);
}
-
- return context;
}
/**
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java
index 8a1ddc5a276..6aedc74a0a1 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractTestContextBootstrapper.java
@@ -35,6 +35,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler;
import org.springframework.lang.Nullable;
+import org.springframework.test.context.ApplicationContextFailureProcessor;
import org.springframework.test.context.BootstrapContext;
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
import org.springframework.test.context.ContextConfiguration;
@@ -494,15 +495,40 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
/**
* Get the {@link CacheAwareContextLoaderDelegate} to use for transparent
* interaction with the {@code ContextCache}.
- * The default implementation simply delegates to - * {@code getBootstrapContext().getCacheAwareContextLoaderDelegate()}. + *
The default implementation delegates to + * {@code getBootstrapContext().getCacheAwareContextLoaderDelegate()} and + * supplies the returned delegate the configured + * {@link #getApplicationContextFailureProcessor() ApplicationContextFailureProcessor}. *
Concrete subclasses may choose to override this method to return a custom * {@code CacheAwareContextLoaderDelegate} implementation with custom * {@link org.springframework.test.context.cache.ContextCache ContextCache} support. * @return the context loader delegate (never {@code null}) + * @see #getApplicationContextFailureProcessor() */ protected CacheAwareContextLoaderDelegate getCacheAwareContextLoaderDelegate() { - return getBootstrapContext().getCacheAwareContextLoaderDelegate(); + CacheAwareContextLoaderDelegate delegate = getBootstrapContext().getCacheAwareContextLoaderDelegate(); + ApplicationContextFailureProcessor contextFailureProcessor = getApplicationContextFailureProcessor(); + if (contextFailureProcessor != null) { + delegate.setContextFailureProcessor(contextFailureProcessor); + } + return delegate; + } + + /** + * Get the {@link ApplicationContextFailureProcessor} to use. + *
The default implementation returns {@code null}. + *
Concrete subclasses may choose to override this method to provide an
+ * {@code ApplicationContextFailureProcessor} that will be supplied to the
+ * configured {@code CacheAwareContextLoaderDelegate} in
+ * {@link #getCacheAwareContextLoaderDelegate()}.
+ * @return the context failure processor to use, or {@code null} if no processor
+ * should be used
+ * @since 6.0
+ * @see #getCacheAwareContextLoaderDelegate()
+ */
+ @Nullable
+ protected ApplicationContextFailureProcessor getApplicationContextFailureProcessor() {
+ return null;
}
/**
diff --git a/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java
index 7153e19e20e..98662fe07ab 100644
--- a/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java
@@ -29,6 +29,7 @@ import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.web.MockServletContext;
+import org.springframework.test.context.ContextLoadException;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.aot.AotContextLoader;
import org.springframework.test.context.support.AbstractContextLoader;
@@ -156,12 +157,17 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
validateMergedContextConfiguration(webMergedConfig);
GenericWebApplicationContext context = createContext();
- configureWebResources(context, webMergedConfig);
- prepareContext(context, webMergedConfig);
- initializer.initialize(context);
- customizeContext(context, webMergedConfig);
- context.refresh();
- return context;
+ try {
+ configureWebResources(context, webMergedConfig);
+ prepareContext(context, webMergedConfig);
+ initializer.initialize(context);
+ customizeContext(context, webMergedConfig);
+ context.refresh();
+ return context;
+ }
+ catch (Exception ex) {
+ throw new ContextLoadException(context, ex);
+ }
}
/**
@@ -194,24 +200,28 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
validateMergedContextConfiguration(webMergedConfig);
GenericWebApplicationContext context = createContext();
+ try {
+ ApplicationContext parent = mergedConfig.getParentApplicationContext();
+ if (parent != null) {
+ context.setParent(parent);
+ }
+ configureWebResources(context, webMergedConfig);
+ prepareContext(context, webMergedConfig);
+ customizeBeanFactory(context.getDefaultListableBeanFactory(), webMergedConfig);
+ loadBeanDefinitions(context, webMergedConfig);
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
+ customizeContext(context, webMergedConfig);
+
+ if (!forAotProcessing) {
+ context.refresh();
+ context.registerShutdownHook();
+ }
- ApplicationContext parent = mergedConfig.getParentApplicationContext();
- if (parent != null) {
- context.setParent(parent);
+ return context;
}
- configureWebResources(context, webMergedConfig);
- prepareContext(context, webMergedConfig);
- customizeBeanFactory(context.getDefaultListableBeanFactory(), webMergedConfig);
- loadBeanDefinitions(context, webMergedConfig);
- AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
- customizeContext(context, webMergedConfig);
-
- if (!forAotProcessing) {
- context.refresh();
- context.registerShutdownHook();
+ catch (Exception ex) {
+ throw new ContextLoadException(context, ex);
}
-
- return context;
}
/**
diff --git a/spring-test/src/test/java/org/springframework/test/context/failures/ContextLoadFailureTests.java b/spring-test/src/test/java/org/springframework/test/context/failures/ContextLoadFailureTests.java
new file mode 100644
index 00000000000..bb40c7cf348
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/failures/ContextLoadFailureTests.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-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.test.context.failures;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.testkit.engine.EngineTestKit;
+
+import org.springframework.beans.BeanInstantiationException;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.test.context.ApplicationContextFailureProcessor;
+import org.springframework.test.context.BootstrapWith;
+import org.springframework.test.context.junit.jupiter.FailingTestCase;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.springframework.test.context.support.DefaultTestContextBootstrapper;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+
+/**
+ * Tests for failures that occur while loading an {@link ApplicationContext}.
+ *
+ * @author Sam Brannen
+ * @since 6.0
+ */
+class ContextLoadFailureTests {
+
+ static List