diff --git a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java index 97841c8c80..5d775e664e 100644 --- a/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/MergedContextConfiguration.java @@ -62,7 +62,7 @@ import org.springframework.util.StringUtils; * @see ActiveProfiles * @see TestPropertySource * @see ContextConfigurationAttributes - * @see SmartContextLoader#loadContext(MergedContextConfiguration) + * @see SmartContextLoader#loadContext(MergedContextConfiguration, boolean) */ public class MergedContextConfiguration implements Serializable { 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 6faf0c5105..dd9474fc1c 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 @@ -25,34 +25,34 @@ import org.springframework.lang.Nullable; * *

The {@code SmartContextLoader} SPI supersedes the {@link ContextLoader} SPI * introduced in Spring 2.5: a {@code SmartContextLoader} can choose to process - * resource locations, annotated classes, or a combination of both. Furthermore, a + * resource locations, component classes, or a combination of both. Furthermore, a * {@code SmartContextLoader} can configure the context that it - * {@linkplain #loadContext(MergedContextConfiguration) loads} based on any - * properties available in the provided {@link MergedContextConfiguration}. For - * example, active bean definition profiles can be configured for the context + * {@linkplain #loadContext(MergedContextConfiguration, boolean) loads} based on + * any properties available in the provided {@link MergedContextConfiguration}. + * For example, active bean definition profiles can be configured for the context * based on {@link MergedContextConfiguration#getActiveProfiles()}. * *

See the Javadoc for {@link ContextConfiguration @ContextConfiguration} - * for a definition of annotated class. + * for a definition of component classes. * *

Clients of a {@code SmartContextLoader} should call * {@link #processContextConfiguration(ContextConfigurationAttributes) * processContextConfiguration()} prior to calling - * {@link #loadContext(MergedContextConfiguration) loadContext()}. This gives a - * {@code SmartContextLoader} the opportunity to provide custom support for - * modifying resource locations or detecting default resource locations or + * {@link #loadContext(MergedContextConfiguration, boolean) loadContext()}. This + * gives a {@code SmartContextLoader} the opportunity to provide custom support + * for modifying resource locations or detecting default resource locations or * default configuration classes. The results of * {@link #processContextConfiguration(ContextConfigurationAttributes) * processContextConfiguration()} should be merged for all classes in the * hierarchy of the root test class and then supplied to - * {@link #loadContext(MergedContextConfiguration) loadContext()}. + * {@link #loadContext(MergedContextConfiguration, boolean) loadContext()}. * *

NOTE: As of Spring Framework 6.0, {@code SmartContextLoader} no longer * supports methods defined in the {@code ContextLoader} SPI. * *

Concrete implementations must provide a {@code public} no-args constructor. * - *

Spring provides the following out-of-the-box implementations: + *

Spring provides the following {@code SmartContextLoader} implementations. *

* @param mergedConfig the merged context configuration to use to load the application context + * @param refresh whether to refresh the {@code ApplicationContext} and register + * a JVM shutdown hook for it + * @return a new application context * @throws IllegalArgumentException if the supplied merged configuration is {@code null} * @throws IllegalStateException if neither candidate loader is capable of loading an * {@code ApplicationContext} from the supplied merged context configuration + * @since 6.0 */ @Override - public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + public ApplicationContext loadContext(MergedContextConfiguration mergedConfig, boolean refresh) throws Exception { Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null"); Assert.state(!(mergedConfig.hasLocations() && mergedConfig.hasClasses()), () -> String.format( @@ -209,7 +225,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte // Determine if each loader can load a context from the mergedConfig. If it // can, let it; otherwise, keep iterating. if (supports(loader, mergedConfig)) { - return delegateLoading(loader, mergedConfig); + return delegateLoading(loader, mergedConfig, refresh); } } @@ -217,7 +233,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte // ACIs or customizers were declared, then delegate to the annotation config // loader. if (!mergedConfig.getContextInitializerClasses().isEmpty() || !mergedConfig.getContextCustomizers().isEmpty()) { - return delegateLoading(getAnnotationConfigLoader(), mergedConfig); + return delegateLoading(getAnnotationConfigLoader(), mergedConfig, refresh); } // else... @@ -235,13 +251,14 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte loader.processContextConfiguration(configAttributes); } - private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig) + private static ApplicationContext delegateLoading( + SmartContextLoader loader, MergedContextConfiguration mergedConfig, boolean refresh) throws Exception { if (logger.isDebugEnabled()) { logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig)); } - return loader.loadContext(mergedConfig); + return loader.loadContext(mergedConfig, refresh); } private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) { 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 38d3130cde..c3843014a3 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * 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. @@ -40,9 +40,9 @@ import org.springframework.util.StringUtils; *
  • If instances of concrete subclasses are invoked via the * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader} * SPI, the context will be loaded from the {@link MergedContextConfiguration} - * provided to {@link #loadContext(MergedContextConfiguration)}. In such cases, a - * {@code SmartContextLoader} will decide whether to load the context from - * locations or annotated classes.
  • + * provided to {@link #loadContext(MergedContextConfiguration, boolean)}. In such + * cases, a {@code SmartContextLoader} will decide whether to load the context + * from locations or annotated classes. * * *

    Concrete subclasses must provide an appropriate implementation of @@ -54,13 +54,23 @@ import org.springframework.util.StringUtils; * @author Juergen Hoeller * @author Phillip Webb * @since 2.5 - * @see #loadContext(MergedContextConfiguration) - * @see #loadContext(String...) + * @see #loadContext(MergedContextConfiguration, boolean) */ public abstract class AbstractGenericContextLoader extends AbstractContextLoader { protected static final Log logger = LogFactory.getLog(AbstractGenericContextLoader.class); + /** + * Although this method is officially deprecated, for backward compatibility + * it delegates to {@link #loadContext(MergedContextConfiguration, boolean)}, + * supplying {@code true} for the {@code refresh} flag. + * @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)} + */ + @Override + @Deprecated + public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + return loadContext(mergedConfig, true); + } /** * Load a Spring ApplicationContext from the supplied {@link MergedContextConfiguration}. @@ -94,15 +104,22 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader *

  • Calls {@link #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration)} to * allow for customizing the context before it is refreshed.
  • *
  • {@link ConfigurableApplicationContext#refresh Refreshes} the - * context and registers a JVM shutdown hook for it.
  • + * context and registers a JVM shutdown hook for it if the supplied the + * {@code refresh} flag is {@code true}. * + * @param mergedConfig the merged context configuration to use to load the + * application context + * @param refresh whether to refresh the {@code ApplicationContext} and register + * a JVM shutdown hook for it * @return a new application context - * @since 3.1 - * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) + * @since 6.0 + * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean) * @see GenericApplicationContext */ @Override - public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + public final ConfigurableApplicationContext loadContext( + MergedContextConfiguration mergedConfig, boolean refresh) throws Exception { + if (logger.isDebugEnabled()) { logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].", mergedConfig)); @@ -124,8 +141,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader customizeContext(context); customizeContext(context, mergedConfig); - context.refresh(); - context.registerShutdownHook(); + if (refresh) { + context.refresh(); + context.registerShutdownHook(); + } return context; } @@ -166,15 +185,15 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * context and registers a JVM shutdown hook for it. * *

    Note: this method does not provide a means to set active bean definition - * profiles for the loaded context. See {@link #loadContext(MergedContextConfiguration)} + * profiles for the loaded context. See {@link #loadContext(MergedContextConfiguration, boolean)} * and {@link AbstractContextLoader#prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)} * for an alternative. * @return a new application context * @since 2.5 * @see org.springframework.test.context.ContextLoader#loadContext * @see GenericApplicationContext - * @see #loadContext(MergedContextConfiguration) - * @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration)} + * @see #loadContext(MergedContextConfiguration, boolean) + * @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)} */ @Deprecated @Override @@ -219,7 +238,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * customize {@code GenericApplicationContext}'s standard settings. * @param context the context that should be prepared * @since 2.5 - * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(MergedContextConfiguration, boolean) * @see #loadContext(String...) * @see GenericApplicationContext#setAllowBeanDefinitionOverriding * @see GenericApplicationContext#setResourceLoader @@ -236,7 +255,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * to customize {@code DefaultListableBeanFactory}'s standard settings. * @param beanFactory the bean factory created by this {@code ContextLoader} * @since 2.5 - * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(MergedContextConfiguration, boolean) * @see #loadContext(String...) * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding * @see DefaultListableBeanFactory#setAllowEagerClassLoading @@ -261,7 +280,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * @param context the context into which the bean definitions should be loaded * @param mergedConfig the merged context configuration * @since 3.1 - * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(MergedContextConfiguration, boolean) */ protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) { createBeanDefinitionReader(context).loadBeanDefinitions(mergedConfig.getLocations()); @@ -288,7 +307,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * to customize the application context. * @param context the newly created application context * @since 2.5 - * @see #loadContext(MergedContextConfiguration) + * @see #loadContext(MergedContextConfiguration, boolean) * @see #loadContext(String...) * @see #customizeContext(ConfigurableApplicationContext, MergedContextConfiguration) */ 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 8260325057..3fb70624c4 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 @@ -64,6 +64,18 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa // SmartContextLoader + /** + * Although this method is officially deprecated, for backward compatibility + * it delegates to {@link #loadContext(MergedContextConfiguration, boolean)}, + * supplying {@code true} for the {@code refresh} flag. + * @deprecated as of Spring Framework 6.0, in favor of {@link #loadContext(MergedContextConfiguration, boolean)} + */ + @Override + @Deprecated + public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + return loadContext(mergedConfig, true); + } + /** * Load a Spring {@link WebApplicationContext} from the supplied * {@link MergedContextConfiguration}. @@ -94,12 +106,19 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa *

  • {@link ConfigurableApplicationContext#refresh Refreshes} the * context and registers a JVM shutdown hook for it.
  • * + * @param mergedConfig the merged context configuration to use to load the + * application context + * @param refresh whether to refresh the {@code ApplicationContext} and register + * a JVM shutdown hook for it * @return a new web application context - * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) + * @since 6.0 + * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean) * @see GenericWebApplicationContext */ @Override - public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { + public final ConfigurableApplicationContext loadContext( + MergedContextConfiguration mergedConfig, boolean refresh) throws Exception { + Assert.isTrue(mergedConfig instanceof WebMergedContextConfiguration, () -> String.format("Cannot load WebApplicationContext from non-web merged context configuration %s. " + "Consider annotating your test class with @WebAppConfiguration.", mergedConfig)); @@ -125,8 +144,12 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa loadBeanDefinitions(context, webMergedConfig); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); customizeContext(context, webMergedConfig); - context.refresh(); - context.registerShutdownHook(); + + if (refresh) { + context.refresh(); + context.registerShutdownHook(); + } + return context; } diff --git a/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java index c0d2819afa..35eece33fb 100644 --- a/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/web/WebMergedContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * 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. @@ -50,7 +50,7 @@ import org.springframework.util.StringUtils; * @see org.springframework.test.context.ContextConfiguration * @see org.springframework.test.context.ActiveProfiles * @see org.springframework.test.context.ContextConfigurationAttributes - * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) + * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration, boolean) */ public class WebMergedContextConfiguration extends MergedContextConfiguration { diff --git a/spring-test/src/test/java/org/springframework/test/context/support/AnnotatedFooConfigInnerClassTestCase.java b/spring-test/src/test/java/org/springframework/test/context/support/AnnotatedFooConfigInnerClassTestCase.java index 21dec677f0..f5150b7c81 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/AnnotatedFooConfigInnerClassTestCase.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/AnnotatedFooConfigInnerClassTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * 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. @@ -28,11 +28,11 @@ import org.springframework.context.annotation.Configuration; */ public class AnnotatedFooConfigInnerClassTestCase { - @Configuration + @Configuration(proxyBeanMethods = false) static class FooConfig { @Bean - public String foo() { + String foo() { return "foo"; } } diff --git a/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java index aaac4af95e..5262d466a8 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * 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. @@ -16,8 +16,11 @@ package org.springframework.test.context.support; +import java.util.Arrays; + import org.junit.jupiter.api.Test; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.test.context.MergedContextConfiguration; import static org.assertj.core.api.Assertions.assertThat; @@ -31,24 +34,54 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; */ class AnnotationConfigContextLoaderTests { - private final AnnotationConfigContextLoader contextLoader = new AnnotationConfigContextLoader(); - private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + private final AnnotationConfigContextLoader contextLoader = new AnnotationConfigContextLoader(); + /** * @since 4.0.4 */ @Test - void configMustNotContainLocations() throws Exception { + void loadContextWithConfigContainingLocationsResultsInException() { MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, contextLoader); - assertThatIllegalStateException().isThrownBy(() -> - contextLoader.loadContext(mergedConfig)) + assertThatIllegalStateException() + .isThrownBy(() -> contextLoader.loadContext(mergedConfig, true)) .withMessageContaining("does not support resource locations"); } + /** + * @since 6.0 + */ + @Test + void loadContextHonorsRefreshTrue() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration( + AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY, + new Class[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class}, + EMPTY_STRING_ARRAY, contextLoader); + ConfigurableApplicationContext context = contextLoader.loadContext(mergedConfig, true); + assertThat(context).isNotNull(); + assertThat(context.isActive()).as("ApplicationContext is active").isTrue(); + assertThat(context.getBean(String.class)).isEqualTo("foo"); + } + + /** + * @since 6.0 + */ + @Test + void loadContextHonorsRefreshFalse() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration( + AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY, + new Class[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class}, + EMPTY_STRING_ARRAY, contextLoader); + ConfigurableApplicationContext context = contextLoader.loadContext(mergedConfig, false); + assertThat(context).isNotNull(); + assertThat(context.isActive()).as("ApplicationContext is active").isFalse(); + assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains("FooConfig")); + } + @Test void detectDefaultConfigurationClassesForAnnotatedInnerClass() { Class[] configClasses = contextLoader.detectDefaultConfigurationClasses(ContextConfigurationInnerClassTestCase.class); diff --git a/spring-test/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java index 6efe5fc183..d929af7c67 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/CustomizedGenericXmlContextLoaderTests.java @@ -53,7 +53,7 @@ class CustomizedGenericXmlContextLoaderTests { MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), null, null, null, null); - customLoader.loadContext(mergedConfig); + customLoader.loadContext(mergedConfig, true); assertThat(customizeInvoked).as("customizeContext() should have been invoked").isTrue(); } diff --git a/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java index 48ad2792a6..de0550b80f 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java @@ -16,6 +16,9 @@ package org.springframework.test.context.support; +import java.util.Arrays; + +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; @@ -25,7 +28,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.ContextLoader; import org.springframework.test.context.MergedContextConfiguration; -import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -45,135 +47,167 @@ class DelegatingSmartContextLoaderTests { private final DelegatingSmartContextLoader loader = new DelegatingSmartContextLoader(); + @Nested + class SmartContextLoaderSpiTests { - private static void assertEmpty(Object[] array) { - assertThat(ObjectUtils.isEmpty(array)).isTrue(); - } + @Test + void processContextConfigurationWithDefaultXmlConfigGeneration() { + ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( + XmlTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); + loader.processContextConfiguration(configAttributes); + assertThat(configAttributes.getLocations()).hasSize(1); + assertThat(configAttributes.getClasses()).isEmpty(); + } - // --- SmartContextLoader - processContextConfiguration() ------------------ + @Test + void processContextConfigurationWithDefaultConfigurationClassGeneration() { + ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( + ConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); + loader.processContextConfiguration(configAttributes); + assertThat(configAttributes.getClasses()).hasSize(1); + assertThat(configAttributes.getLocations()).isEmpty(); + } - @Test - void processContextConfigurationWithDefaultXmlConfigGeneration() { - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( - XmlTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); - loader.processContextConfiguration(configAttributes); - assertThat(configAttributes.getLocations().length).isEqualTo(1); - assertEmpty(configAttributes.getClasses()); - } + @Test + void processContextConfigurationWithDefaultXmlConfigAndConfigurationClassGeneration() { + ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( + ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, + true, null, true, ContextLoader.class); + assertThatIllegalStateException() + .isThrownBy(() -> loader.processContextConfiguration(configAttributes)) + .withMessageContaining("both default locations AND default configuration classes were detected"); + } - @Test - void processContextConfigurationWithDefaultConfigurationClassGeneration() { - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( - ConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); - loader.processContextConfiguration(configAttributes); - assertThat(configAttributes.getClasses().length).isEqualTo(1); - assertEmpty(configAttributes.getLocations()); - } + @Test + void processContextConfigurationWithLocation() { + String[] locations = new String[] {"classpath:/foo.xml"}; + ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( + getClass(), locations, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); + loader.processContextConfiguration(configAttributes); + assertThat(configAttributes.getLocations()).isEqualTo(locations); + assertThat(configAttributes.getClasses()).isEmpty(); + } - @Test - void processContextConfigurationWithDefaultXmlConfigAndConfigurationClassGeneration() { - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( - ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, - true, null, true, ContextLoader.class); - assertThatIllegalStateException().isThrownBy(() -> - loader.processContextConfiguration(configAttributes)) - .withMessageContaining("both default locations AND default configuration classes were detected"); - } + @Test + void processContextConfigurationWithConfigurationClass() { + Class[] classes = new Class[] {getClass()}; + ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( + getClass(), EMPTY_STRING_ARRAY, classes, true, null, true, ContextLoader.class); + loader.processContextConfiguration(configAttributes); + assertThat(configAttributes.getClasses()).isEqualTo(classes); + assertThat(configAttributes.getLocations()).isEmpty(); + } - @Test - void processContextConfigurationWithLocation() { - String[] locations = new String[] {"classpath:/foo.xml"}; - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( - getClass(), locations, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); - loader.processContextConfiguration(configAttributes); - assertThat(configAttributes.getLocations()).isEqualTo(locations); - assertEmpty(configAttributes.getClasses()); - } + @Test + void loadContextWithNullConfig() throws Exception { + assertThatIllegalArgumentException().isThrownBy(() -> loader.loadContext(null, true)); + } - @Test - void processContextConfigurationWithConfigurationClass() { - Class[] classes = new Class[] {getClass()}; - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( - getClass(), EMPTY_STRING_ARRAY, classes, true, null, true, ContextLoader.class); - loader.processContextConfiguration(configAttributes); - assertThat(configAttributes.getClasses()).isEqualTo(classes); - assertEmpty(configAttributes.getLocations()); - } + @Test + void loadContextWithoutLocationsAndConfigurationClasses() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration( + getClass(), EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader); + assertThatIllegalStateException() + .isThrownBy(() -> loader.loadContext(mergedConfig, true)) + .withMessageStartingWith("Neither") + .withMessageContaining("was able to load an ApplicationContext from"); + } - // --- SmartContextLoader - loadContext() ---------------------------------- + /** + * @since 4.1 + */ + @Test + void loadContextWithLocationsAndConfigurationClasses() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), + new String[] {"test.xml"}, new Class[] {getClass()}, EMPTY_STRING_ARRAY, loader); + assertThatIllegalStateException() + .isThrownBy(() -> loader.loadContext(mergedConfig, true)) + .withMessageStartingWith("Neither") + .withMessageContaining("declare either 'locations' or 'classes' but not both."); + } - @Test - void loadContextWithNullConfig() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - loader.loadContext((MergedContextConfiguration) null)); - } + @Test + void loadContextWithXmlConfig() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration( + XmlTestCase.class, + new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"}, + EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader); - @Test - void loadContextWithoutLocationsAndConfigurationClasses() throws Exception { - MergedContextConfiguration mergedConfig = new MergedContextConfiguration( - getClass(), EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader); - assertThatIllegalStateException().isThrownBy(() -> - loader.loadContext(mergedConfig)) - .withMessageStartingWith("Neither") - .withMessageContaining("was able to load an ApplicationContext from"); - } + assertApplicationContextLoadsAndContainsFooString(mergedConfig); + } - /** - * @since 4.1 - */ - @Test - void loadContextWithLocationsAndConfigurationClasses() throws Exception { - MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), - new String[] {"test.xml"}, new Class[] {getClass()}, EMPTY_STRING_ARRAY, loader); - assertThatIllegalStateException().isThrownBy(() -> - loader.loadContext(mergedConfig)) - .withMessageStartingWith("Neither") - .withMessageContaining("declare either 'locations' or 'classes' but not both."); - } + @Test + void loadContextWithConfigurationClass() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class, + EMPTY_STRING_ARRAY, new Class[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader); - private void assertApplicationContextLoadsAndContainsFooString(MergedContextConfiguration mergedConfig) - throws Exception { + assertApplicationContextLoadsAndContainsFooString(mergedConfig); + } - ApplicationContext applicationContext = loader.loadContext(mergedConfig); - assertThat(applicationContext).isNotNull(); - assertThat(applicationContext.getBean(String.class)).isEqualTo("foo"); - boolean condition = applicationContext instanceof ConfigurableApplicationContext; - assertThat(condition).isTrue(); - ((ConfigurableApplicationContext) applicationContext).close(); - } + private void assertApplicationContextLoadsAndContainsFooString(MergedContextConfiguration mergedConfig) + throws Exception { - @Test - void loadContextWithXmlConfig() throws Exception { - MergedContextConfiguration mergedConfig = new MergedContextConfiguration( - XmlTestCase.class, - new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"}, - EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader); - assertApplicationContextLoadsAndContainsFooString(mergedConfig); - } + ApplicationContext applicationContext = loader.loadContext(mergedConfig, true); + assertThat(applicationContext).isInstanceOf(ConfigurableApplicationContext.class); + assertThat(applicationContext.getBean(String.class)).isEqualTo("foo"); + ConfigurableApplicationContext cac = (ConfigurableApplicationContext) applicationContext; + cac.close(); + } - @Test - void loadContextWithConfigurationClass() throws Exception { - MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class, - EMPTY_STRING_ARRAY, new Class[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader); - assertApplicationContextLoadsAndContainsFooString(mergedConfig); - } + /** + * @since 6.0 + */ + @Test + void loadContextWithXmlConfigWithoutRefresh() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration( + XmlTestCase.class, + new String[] {"classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml"}, + EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader); + + assertApplicationContextLoadsWithoutRefresh(mergedConfig, "foo"); + } - // --- ContextLoader ------------------------------------------------------- + /** + * @since 6.0 + */ + @Test + void loadContextWithConfigurationClassWithoutRefresh() throws Exception { + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class, + EMPTY_STRING_ARRAY, new Class[] {ConfigClassTestCase.Config.class}, EMPTY_STRING_ARRAY, loader); - @Test - void processLocations() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> - loader.processLocations(getClass(), EMPTY_STRING_ARRAY)); - } + assertApplicationContextLoadsWithoutRefresh(mergedConfig, "ConfigClassTestCase.Config"); + } + + private void assertApplicationContextLoadsWithoutRefresh(MergedContextConfiguration mergedConfig, + String expectedBeanDefName) throws Exception { + + ApplicationContext context = loader.loadContext(mergedConfig, false); + assertThat(context).isInstanceOf(ConfigurableApplicationContext.class); + ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context; + assertThat(cac.isActive()).as("ApplicationContext is active").isFalse(); + assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains(expectedBeanDefName)); + cac.close(); + } - @Test - void loadContextFromLocations() { - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> - loader.loadContext(EMPTY_STRING_ARRAY)); } + @Nested + class ContextLoaderSpiTests { + + @Test + void processLocations() { + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> loader.processLocations(getClass(), EMPTY_STRING_ARRAY)); + } + + @Test + void loadContextFromLocations() { + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> loader.loadContext(EMPTY_STRING_ARRAY)); + } + + } - // ------------------------------------------------------------------------- static class XmlTestCase { } diff --git a/spring-test/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderTests.java index 0b3960fd5c..33755b80d2 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/GenericXmlContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * 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. @@ -40,7 +40,7 @@ class GenericXmlContextLoaderTests { MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), EMPTY_STRING_ARRAY, new Class[] { getClass() }, EMPTY_STRING_ARRAY, loader); assertThatIllegalStateException() - .isThrownBy(() -> loader.loadContext(mergedConfig)) + .isThrownBy(() -> loader.loadContext(mergedConfig, true)) .withMessageContaining("does not support annotated classes"); } diff --git a/spring-test/src/test/java/org/springframework/test/context/web/AnnotationConfigWebContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/web/AnnotationConfigWebContextLoaderTests.java index 221f84c29e..f5921a8c43 100644 --- a/spring-test/src/test/java/org/springframework/test/context/web/AnnotationConfigWebContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/web/AnnotationConfigWebContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * 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. @@ -39,7 +39,7 @@ class AnnotationConfigWebContextLoaderTests { new String[] { "config.xml" }, EMPTY_CLASS_ARRAY, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, "resource/path", loader, null, null); assertThatIllegalStateException() - .isThrownBy(() -> loader.loadContext(mergedConfig)) + .isThrownBy(() -> loader.loadContext(mergedConfig, true)) .withMessageContaining("does not support resource locations"); } diff --git a/spring-test/src/test/java/org/springframework/test/context/web/GenericXmlWebContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/web/GenericXmlWebContextLoaderTests.java index e6fc82e65b..17bb1034a2 100644 --- a/spring-test/src/test/java/org/springframework/test/context/web/GenericXmlWebContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/web/GenericXmlWebContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * 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. @@ -38,7 +38,7 @@ class GenericXmlWebContextLoaderTests { new Class[] { getClass() }, null, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, "resource/path", loader, null, null); assertThatIllegalStateException() - .isThrownBy(() -> loader.loadContext(mergedConfig)) + .isThrownBy(() -> loader.loadContext(mergedConfig, true)) .withMessageContaining("does not support annotated classes"); }