diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java index 00d9c714eb..fa192d3ff0 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java @@ -196,8 +196,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao else { application.setWebApplicationType(WebApplicationType.NONE); } - application.setApplicationContextFactory( - (webApplicationType) -> getApplicationContextFactory(mergedConfig, webApplicationType)); + application.setApplicationContextFactory(getApplicationContextFactory(mergedConfig)); if (mergedConfig.getParent() != null) { application.setBannerMode(Banner.Mode.OFF); } @@ -212,17 +211,26 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao } } - private ConfigurableApplicationContext getApplicationContextFactory(MergedContextConfiguration mergedConfig, - WebApplicationType webApplicationType) { - if (webApplicationType != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) { - if (webApplicationType == WebApplicationType.REACTIVE) { - return new GenericReactiveWebApplicationContext(); + /** + * Return the {@link ApplicationContextFactory} that should be used for the test. By + * default this method will return a factory that will create an appropriate + * {@link ApplicationContext} for the {@link WebApplicationType}. + * @param mergedConfig the merged context configuration + * @return the application context factory to use + * @since 3.2.0 + */ + protected ApplicationContextFactory getApplicationContextFactory(MergedContextConfiguration mergedConfig) { + return (webApplicationType) -> { + if (webApplicationType != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) { + if (webApplicationType == WebApplicationType.REACTIVE) { + return new GenericReactiveWebApplicationContext(); + } + if (webApplicationType == WebApplicationType.SERVLET) { + return new GenericWebApplicationContext(); + } } - if (webApplicationType == WebApplicationType.SERVLET) { - return new GenericWebApplicationContext(); - } - } - return ApplicationContextFactory.DEFAULT.create(webApplicationType); + return ApplicationContextFactory.DEFAULT.create(webApplicationType); + }; } private void prepareEnvironment(MergedContextConfiguration mergedConfig, SpringApplication application, diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java index 5102e242d5..ee8777e176 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java @@ -26,12 +26,14 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.ApplicationContextFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest.UseMainMethod; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext; import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; @@ -246,6 +248,13 @@ class SpringBootContextLoaderTests { .withMessage("UseMainMethod.ALWAYS cannot be used with @ContextHierarchy tests"); } + @Test + void whenSubclassProvidesCustomApplicationContextFactory() { + TestContext testContext = new ExposedTestContextManager(CustomApplicationContextTest.class) + .getExposedTestContext(); + assertThat(testContext.getApplicationContext()).isInstanceOf(CustomAnnotationConfigApplicationContext.class); + } + private String[] getActiveProfiles(Class testClass) { TestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext(); ApplicationContext applicationContext = testContext.getApplicationContext(); @@ -370,6 +379,25 @@ class SpringBootContextLoaderTests { } + @SpringBootTest + @ContextConfiguration(classes = Config.class, loader = CustomApplicationContextSpringBootContextLoader.class) + static class CustomApplicationContextTest { + + } + + static class CustomApplicationContextSpringBootContextLoader extends SpringBootContextLoader { + + @Override + protected ApplicationContextFactory getApplicationContextFactory(MergedContextConfiguration mergedConfig) { + return (webApplicationType) -> new CustomAnnotationConfigApplicationContext(); + } + + } + + static class CustomAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext { + + } + @Configuration(proxyBeanMethods = false) static class Config {