diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java b/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java index 0e0feb47f96..652a6850091 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -34,6 +34,7 @@ import org.springframework.util.StringUtils; * attributes declared via {@link ContextConfiguration @ContextConfiguration}. * * @author Sam Brannen + * @author Phillip Webb * @since 3.1 * @see ContextConfiguration * @see SmartContextLoader#processContextConfiguration(ContextConfigurationAttributes) @@ -43,6 +44,10 @@ public class ContextConfigurationAttributes { private static final Log logger = LogFactory.getLog(ContextConfigurationAttributes.class); + private static final String[] EMPTY_LOCATIONS = new String[0]; + + private static final Class[] EMPTY_CLASSES = new Class[0]; + private final Class declaringClass; private Class[] classes; @@ -60,6 +65,18 @@ public class ContextConfigurationAttributes { private final Class contextLoaderClass; + /** + * Construct a new {@link ContextConfigurationAttributes} instance with default + * values. + * @param declaringClass the test class that declared {@code @ContextConfiguration}, + * either explicitly or implicitly + * @since 4.3 + */ + @SuppressWarnings("unchecked") + public ContextConfigurationAttributes(Class declaringClass) { + this(declaringClass, EMPTY_LOCATIONS, EMPTY_CLASSES, false, (Class[]) EMPTY_CLASSES, true, ContextLoader.class); + } + /** * Construct a new {@link ContextConfigurationAttributes} instance for the * supplied {@link ContextConfiguration @ContextConfiguration} annotation and @@ -158,7 +175,8 @@ public class ContextConfigurationAttributes { /** * Get the {@linkplain Class class} that declared the - * {@link ContextConfiguration @ContextConfiguration} annotation. + * {@link ContextConfiguration @ContextConfiguration} annotation, either explicitly + * or implicitly. * @return the declaring class (never {@code null}) */ public Class getDeclaringClass() { diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java index ca60c8dd3cd..8f942194f98 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -29,7 +29,6 @@ import org.springframework.test.context.ContextLoader; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.SmartContextLoader; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * {@code AbstractDelegatingSmartContextLoader} serves as an abstract base class @@ -202,15 +201,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte name(getAnnotationConfigLoader()), configAttributes)); } - // If neither loader detected defaults and no initializers were declared, - // throw an exception. - if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) { - throw new IllegalStateException(String.format( - "Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers " - + "were declared for context configuration %s", name(getXmlLoader()), - name(getAnnotationConfigLoader()), configAttributes)); - } - if (configAttributes.hasLocations() && configAttributes.hasClasses()) { String message = String.format( "Configuration error: both default locations AND default configuration classes " 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 e03b89625be..ab87d056f72 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -18,6 +18,7 @@ package org.springframework.test.context.support; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; @@ -30,8 +31,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanUtils; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.support.SpringFactoriesLoader; @@ -71,6 +70,7 @@ import org.springframework.util.StringUtils; * * @author Sam Brannen * @author Juergen Hoeller + * @author Phillip Webb * @since 4.1 */ public abstract class AbstractTestContextBootstrapper implements TestContextBootstrapper { @@ -272,13 +272,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate = getCacheAwareContextLoaderDelegate(); if (MetaAnnotationUtils.findAnnotationDescriptorForTypes(testClass, ContextConfiguration.class, - ContextHierarchy.class) == null) { - if (logger.isInfoEnabled()) { - logger.info(String.format( - "Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]", - testClass.getName())); - } - return new MergedContextConfiguration(testClass, null, null, null, null); + ContextHierarchy.class) == null) { + return buildDefaultMergedContextConfiguration(testClass, cacheAwareContextLoaderDelegate); } if (AnnotationUtils.findAnnotation(testClass, ContextHierarchy.class) != null) { @@ -297,7 +292,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot Class declaringClass = reversedList.get(0).getDeclaringClass(); mergedConfig = buildMergedContextConfiguration(declaringClass, reversedList, parentConfig, - cacheAwareContextLoaderDelegate); + cacheAwareContextLoaderDelegate, true); parentConfig = mergedConfig; } @@ -307,10 +302,29 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot else { return buildMergedContextConfiguration(testClass, ContextLoaderUtils.resolveContextConfigurationAttributes(testClass), null, - cacheAwareContextLoaderDelegate); + cacheAwareContextLoaderDelegate, true); } } + /** + * @since 4.3 + */ + private MergedContextConfiguration buildDefaultMergedContextConfiguration(Class testClass, + CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) { + + List defaultConfigAttributesList + = Collections.singletonList(new ContextConfigurationAttributes(testClass)); + + ContextLoader contextLoader = resolveContextLoader(testClass, defaultConfigAttributesList); + if (logger.isInfoEnabled()) { + logger.info(String.format( + "Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s], using %s", + testClass.getName(), contextLoader.getClass().getSimpleName())); + } + return buildMergedContextConfiguration(testClass, defaultConfigAttributesList, null, + cacheAwareContextLoaderDelegate, false); + } + /** * Build the {@link MergedContextConfiguration merged context configuration} * for the supplied {@link Class testClass}, context configuration attributes, @@ -324,6 +338,9 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot * context in a context hierarchy, or {@code null} if there is no parent * @param cacheAwareContextLoaderDelegate the cache-aware context loader delegate to * be passed to the {@code MergedContextConfiguration} constructor + * @param requireLocationsClassesOrInitializers whether locations, classes, or + * initializers are required; typically {@code true} but may be set to {@code false} + * if the configured loader supports empty configuration * @return the merged context configuration * @see #resolveContextLoader * @see ContextLoaderUtils#resolveContextConfigurationAttributes @@ -335,11 +352,15 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot */ private MergedContextConfiguration buildMergedContextConfiguration(Class testClass, List configAttributesList, MergedContextConfiguration parentConfig, - CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) { + CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, + boolean requireLocationsClassesOrInitializers) { + + Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty"); ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList); - List locationsList = new ArrayList(); - List> classesList = new ArrayList>(); + List locations = new ArrayList(); + List> classes = new ArrayList>(); + List> initializers = new ArrayList>(); for (ContextConfigurationAttributes configAttributes : configAttributesList) { if (logger.isTraceEnabled()) { @@ -349,34 +370,53 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot if (contextLoader instanceof SmartContextLoader) { SmartContextLoader smartContextLoader = (SmartContextLoader) contextLoader; smartContextLoader.processContextConfiguration(configAttributes); - locationsList.addAll(0, Arrays.asList(configAttributes.getLocations())); - classesList.addAll(0, Arrays.asList(configAttributes.getClasses())); + locations.addAll(0, Arrays.asList(configAttributes.getLocations())); + classes.addAll(0, Arrays.asList(configAttributes.getClasses())); } else { - String[] processedLocations = contextLoader.processLocations(configAttributes.getDeclaringClass(), - configAttributes.getLocations()); - locationsList.addAll(0, Arrays.asList(processedLocations)); + String[] processedLocations = contextLoader.processLocations( + configAttributes.getDeclaringClass(), configAttributes.getLocations()); + locations.addAll(0, Arrays.asList(processedLocations)); // Legacy ContextLoaders don't know how to process classes } + initializers.addAll(0, Arrays.asList(configAttributes.getInitializers())); if (!configAttributes.isInheritLocations()) { break; } } - String[] locations = StringUtils.toStringArray(locationsList); - Class[] classes = ClassUtils.toClassArray(classesList); - Set>> initializerClasses = // - ApplicationContextInitializerUtils.resolveInitializerClasses(configAttributesList); - String[] activeProfiles = ActiveProfilesUtils.resolveActiveProfiles(testClass); - MergedTestPropertySources mergedTestPropertySources = TestPropertySourceUtils.buildMergedTestPropertySources(testClass); + if (requireLocationsClassesOrInitializers && areAllEmpty(locations, classes, initializers)) { + throw new IllegalStateException(String.format( + "%s was unable to detect defaults, and no ApplicationContextInitializers " + + "were declared for context configuration attributes %s", + contextLoader.getClass().getSimpleName(), configAttributesList)); + } - MergedContextConfiguration mergedConfig = new MergedContextConfiguration(testClass, locations, classes, - initializerClasses, activeProfiles, mergedTestPropertySources.getLocations(), - mergedTestPropertySources.getProperties(), contextLoader, cacheAwareContextLoaderDelegate, parentConfig); + MergedTestPropertySources mergedTestPropertySources = TestPropertySourceUtils.buildMergedTestPropertySources(testClass); + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(testClass, + StringUtils.toStringArray(locations), + ClassUtils.toClassArray(classes), + ApplicationContextInitializerUtils.resolveInitializerClasses(configAttributesList), + ActiveProfilesUtils.resolveActiveProfiles(testClass), + mergedTestPropertySources.getLocations(), + mergedTestPropertySources.getProperties(), + contextLoader, cacheAwareContextLoaderDelegate, parentConfig); return processMergedContextConfiguration(mergedConfig); } + /** + * @since 4.3 + */ + private boolean areAllEmpty(Collection... collections) { + for (Collection collection : collections) { + if (!collection.isEmpty()) { + return false; + } + } + return true; + } + /** * Resolve the {@link ContextLoader} {@linkplain Class class} to use for the * supplied list of {@link ContextConfigurationAttributes} and then instantiate @@ -389,7 +429,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot * @param testClass the test class for which the {@code ContextLoader} should be * resolved; must not be {@code null} * @param configAttributesList the list of configuration attributes to process; must - * not be {@code null} or empty; must be ordered bottom-up + * not be {@code null}; must be ordered bottom-up * (i.e., as if we were traversing up the class hierarchy) * @return the resolved {@code ContextLoader} for the supplied {@code testClass} * (never {@code null}) @@ -400,7 +440,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot List configAttributesList) { Assert.notNull(testClass, "Class must not be null"); - Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be empty"); + Assert.notNull(configAttributesList, "ContextConfigurationAttributes list must not be null"); Class contextLoaderClass = resolveExplicitContextLoaderClass(configAttributesList); if (contextLoaderClass == null) { @@ -429,7 +469,7 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot * step #1. * * @param configAttributesList the list of configuration attributes to process; - * must not be {@code null} or empty; must be ordered bottom-up + * must not be {@code null}; must be ordered bottom-up * (i.e., as if we were traversing up the class hierarchy) * @return the {@code ContextLoader} class to use for the supplied configuration * attributes, or {@code null} if no explicit loader is found @@ -439,7 +479,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot protected Class resolveExplicitContextLoaderClass( List configAttributesList) { - Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be empty"); + Assert.notNull(configAttributesList, "ContextConfigurationAttributes list must not be null"); + for (ContextConfigurationAttributes configAttributes : configAttributesList) { if (logger.isTraceEnabled()) { logger.trace(String.format("Resolving ContextLoader for context configuration attributes %s", diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/OptionalContextConfigurationSpringRunnerTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/OptionalContextConfigurationSpringRunnerTests.java new file mode 100644 index 00000000000..5cb4ce83776 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit4/OptionalContextConfigurationSpringRunnerTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2016 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 + * + * http://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.junit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.junit.Assert.assertEquals; + +/** + * JUnit 4 based integration test which verifies that {@link @ContextConfiguration} + * is optional. + * + * @author Phillip Webb + * @author Sam Brannen + * @since 4.3 + */ +@RunWith(SpringRunner.class) +public class OptionalContextConfigurationSpringRunnerTests { + + @Autowired + String foo; + + + @Test + public void contextConfigurationAnnotationIsOptional() { + assertEquals("foo", foo); + } + + + @Configuration + static class Config { + + @Bean + String foo() { + return "foo"; + } + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java index 4b70a8cb7d9..f92c74183a4 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsContextInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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,6 +16,7 @@ package org.springframework.test.context.support; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -35,63 +36,62 @@ import org.springframework.web.context.support.GenericWebApplicationContext; * @author Sam Brannen * @since 3.1 */ +@SuppressWarnings("unchecked") public class BootstrapTestUtilsContextInitializerTests extends AbstractContextConfigurationUtilsTests { @Test - public void buildMergedConfigWithLocalInitializer() { - Class testClass = InitializersFoo.class; - Class[] expectedClasses = new Class[] { FooConfig.class }; - Set>> expectedInitializerClasses// - = new HashSet>>(); - expectedInitializerClasses.add(FooInitializer.class); + public void buildMergedConfigWithSingleLocalInitializer() { + Class testClass = SingleInitializer.class; + MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); + + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, + initializers(FooInitializer.class), DelegatingSmartContextLoader.class); + } + @Test + public void buildMergedConfigWithLocalInitializerAndConfigClass() { + Class testClass = InitializersFoo.class; MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); - assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses, expectedInitializerClasses, - DelegatingSmartContextLoader.class); + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, classes(FooConfig.class), + initializers(FooInitializer.class), DelegatingSmartContextLoader.class); } @Test public void buildMergedConfigWithLocalAndInheritedInitializer() { Class testClass = InitializersBar.class; - Class[] expectedClasses = new Class[] { FooConfig.class, BarConfig.class }; - Set>> expectedInitializerClasses// - = new HashSet>>(); - expectedInitializerClasses.add(FooInitializer.class); - expectedInitializerClasses.add(BarInitializer.class); - MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); - assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses, expectedInitializerClasses, - DelegatingSmartContextLoader.class); + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, classes(FooConfig.class, BarConfig.class), + initializers(FooInitializer.class, BarInitializer.class), DelegatingSmartContextLoader.class); } @Test public void buildMergedConfigWithOverriddenInitializers() { Class testClass = OverriddenInitializersBar.class; - Class[] expectedClasses = new Class[] { FooConfig.class, BarConfig.class }; - Set>> expectedInitializerClasses// - = new HashSet>>(); - expectedInitializerClasses.add(BarInitializer.class); - MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); - assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses, expectedInitializerClasses, - DelegatingSmartContextLoader.class); + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, classes(FooConfig.class, BarConfig.class), + initializers(BarInitializer.class), DelegatingSmartContextLoader.class); } @Test public void buildMergedConfigWithOverriddenInitializersAndClasses() { Class testClass = OverriddenInitializersAndClassesBar.class; - Class[] expectedClasses = new Class[] { BarConfig.class }; - Set>> expectedInitializerClasses// - = new HashSet>>(); - expectedInitializerClasses.add(BarInitializer.class); - MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); - assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses, expectedInitializerClasses, - DelegatingSmartContextLoader.class); + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, classes(BarConfig.class), + initializers(BarInitializer.class), DelegatingSmartContextLoader.class); + } + + private Set>> initializers( + Class>... classes) { + + return new HashSet<>(Arrays.asList(classes)); + } + + private Class[] classes(Class... classes) { + return classes; } @@ -109,6 +109,10 @@ public class BootstrapTestUtilsContextInitializerTests extends AbstractContextCo } } + @ContextConfiguration(initializers = FooInitializer.class) + private static class SingleInitializer { + } + @ContextConfiguration(classes = FooConfig.class, initializers = FooInitializer.class) private static class InitializersFoo { } diff --git a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsMergedConfigTests.java b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsMergedConfigTests.java index cef782e28e1..44a780d23f9 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsMergedConfigTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/BootstrapTestUtilsMergedConfigTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -21,15 +21,20 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.test.context.BootstrapTestUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextLoader; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.web.WebDelegatingSmartContextLoader; import org.springframework.test.context.web.WebMergedContextConfiguration; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; /** * Unit tests for {@link BootstrapTestUtils} involving {@link MergedContextConfiguration}. @@ -39,12 +44,28 @@ import static org.junit.Assert.*; */ public class BootstrapTestUtilsMergedConfigTests extends AbstractContextConfigurationUtilsTests { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test - public void buildMergedConfigWithoutAnnotation() { + public void buildImplicitMergedConfigWithoutAnnotation() { Class testClass = Enigma.class; MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); - assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, null); + assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, DelegatingSmartContextLoader.class); + } + + /** + * @since 4.3 + */ + @Test + public void buildMergedConfigWithContextConfigurationWithoutLocationsClassesOrInitializers() { + exception.expect(IllegalStateException.class); + exception.expectMessage(startsWith("DelegatingSmartContextLoader was unable to detect defaults, " + + "and no ApplicationContextInitializers were declared for context configuration attributes")); + + buildMergedContextConfiguration(MissingContextAttributesTestCase.class); } @Test @@ -200,4 +221,8 @@ public class BootstrapTestUtilsMergedConfigTests extends AbstractContextConfigur public static class GermanShepherd extends WorkingDog { } + @ContextConfiguration + static class MissingContextAttributesTestCase { + } + } 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 0395ee36b2c..8f416cfaa45 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -55,17 +55,6 @@ public class DelegatingSmartContextLoaderTests { // --- SmartContextLoader - processContextConfiguration() ------------------ - @Test - public void processContextConfigurationWithoutLocationsAndConfigurationClassesForBogusTestClass() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(startsWith("Neither")); - expectedException.expectMessage(containsString("was able to detect defaults")); - - ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(getClass(), - EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); - loader.processContextConfiguration(configAttributes); - } - @Test public void processContextConfigurationWithDefaultXmlConfigGeneration() { ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(XmlTestCase.class, diff --git a/src/asciidoc/whats-new.adoc b/src/asciidoc/whats-new.adoc index 4dda5d784c7..94c69ef568d 100644 --- a/src/asciidoc/whats-new.adoc +++ b/src/asciidoc/whats-new.adoc @@ -686,6 +686,8 @@ Spring 4.3 also improves the caching abstraction as follows: * The JUnit support in the _Spring TestContext Framework_ now requires JUnit 4.12 or higher. * New `SpringRunner` __alias__ for the `SpringJUnit4ClassRunner`. +* An empty declaration of `@ContextConfiguration` can now be completely omitted if default + XML files, Groovy scripts, or `@Configuration` classes are detected. * `@BeforeTransaction` and `@AfterTransaction` methods are no longer required to be `public`. * Server-side Spring MVC Test supports expectations on response headers with multiple values. * Server-side Spring MVC Test parses form data request content and populates request parameters.