/** * Resolve the {@link ContextLoader} {@linkplain Class class} to use for the * supplied list of {@link ContextConfigurationAttributes} and then instantiate * and return that {@code ContextLoader}. * <p>If the user has not explicitly declared which loader to use, the value * returned from {@link #getDefaultContextLoaderClass} will be used as the * default context loader class. For details on the class resolution process, * see {@link #resolveExplicitContextLoaderClass} and * {@link #getDefaultContextLoaderClass}. * @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 <em>empty</em>; must be ordered <em>bottom-up</em> * (i.e., as if we were traversing up the class hierarchy) * @return the resolved {@code ContextLoader} for the supplied {@code testClass} * (never {@code null}) * @throws IllegalStateException if {@link #getDefaultContextLoaderClass(Class)} * returns {@code null} */ protected ContextLoader resolveContextLoader(Class<?> testClass, List<ContextConfigurationAttributes> configAttributesList) { Assert.notNull(testClass, "Class must not be null"); Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be empty"); Class<? extends ContextLoader> contextLoaderClass = resolveExplicitContextLoaderClass(configAttributesList); if (contextLoaderClass == null) { contextLoaderClass = getDefaultContextLoaderClass(testClass); if (contextLoaderClass == null) { throw new IllegalStateException("getDefaultContextLoaderClass() must not return null"); } } if (logger.isTraceEnabled()) { logger.trace(String.format("Using ContextLoader class [%s] for test class [%s]", contextLoaderClass.getName(), testClass.getName())); } return BeanUtils.instantiateClass(contextLoaderClass, ContextLoader.class); }
/** * Resolve the {@link ContextLoader} {@linkplain Class class} to use for the supplied * list of {@link ContextConfigurationAttributes}. * <p>Beginning with the first level in the context configuration attributes hierarchy: * <ol> * <li>If the {@link ContextConfigurationAttributes#getContextLoaderClass() * contextLoaderClass} property of {@link ContextConfigurationAttributes} is * configured with an explicit class, that class will be returned.</li> * <li>If an explicit {@code ContextLoader} class is not specified at the current * level in the hierarchy, traverse to the next level in the hierarchy and return to * step #1.</li> * </ol> * @param configAttributesList the list of configuration attributes to process; * must not be {@code null} or <em>empty</em>; must be ordered <em>bottom-up</em> * (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 * @throws IllegalArgumentException if supplied configuration attributes are * {@code null} or <em>empty</em> */ protected Class<? extends ContextLoader> resolveExplicitContextLoaderClass( List<ContextConfigurationAttributes> configAttributesList) { Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be empty"); for (ContextConfigurationAttributes configAttributes : configAttributesList) { if (logger.isTraceEnabled()) { logger.trace(String.format("Resolving ContextLoader for context configuration attributes %s", configAttributes)); } Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass(); if (ContextLoader.class != contextLoaderClass) { if (logger.isDebugEnabled()) { logger.debug(String.format( "Found explicit ContextLoader class [%s] for context configuration attributes %s", contextLoaderClass.getName(), configAttributes)); } return contextLoaderClass; } } return null; }
/** * Load the {@code ApplicationContext} for the supplied merged context configuration. * <p>Supports both the {@link SmartContextLoader} and {@link ContextLoader} SPIs. * @throws Exception if an error occurs while loading the application context */ protected ApplicationContext loadContextInternal(MergedContextConfiguration mergedContextConfiguration) throws Exception { ContextLoader contextLoader = mergedContextConfiguration.getContextLoader(); Assert.notNull(contextLoader, "Cannot load an ApplicationContext with a NULL 'contextLoader'. " + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); ApplicationContext applicationContext; if (contextLoader instanceof SmartContextLoader) { SmartContextLoader smartContextLoader = (SmartContextLoader) contextLoader; applicationContext = smartContextLoader.loadContext(mergedContextConfiguration); } else { String[] locations = mergedContextConfiguration.getLocations(); Assert.notNull(locations, "Cannot load an ApplicationContext with a NULL 'locations' array. " + "Consider annotating your test class with @ContextConfiguration or @ContextHierarchy."); applicationContext = contextLoader.loadContext(locations); } return applicationContext; }
@Test public void assertContextConfigurationLocations() throws Exception { final ContextConfiguration contextConfig = this.testClass.getAnnotation(ContextConfiguration.class); final ContextLoader contextLoader = new GenericXmlContextLoader(); final String[] configuredLocations = (String[]) AnnotationUtils.getValue(contextConfig); final String[] processedLocations = contextLoader.processLocations(this.testClass, configuredLocations); if (logger.isDebugEnabled()) { logger.debug("----------------------------------------------------------------------"); logger.debug("Configured locations: " + ObjectUtils.nullSafeToString(configuredLocations)); logger.debug("Expected locations: " + ObjectUtils.nullSafeToString(this.expectedLocations)); logger.debug("Processed locations: " + ObjectUtils.nullSafeToString(processedLocations)); } assertArrayEquals("Verifying locations for test [" + this.testClass + "].", this.expectedLocations, processedLocations); }
void assertMergedConfig( MergedContextConfiguration mergedConfig, Class<?> expectedTestClass, String[] expectedLocations, Class<?>[] expectedClasses, Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> expectedInitializerClasses, Class<? extends ContextLoader> expectedContextLoaderClass) { assertNotNull(mergedConfig); assertEquals(expectedTestClass, mergedConfig.getTestClass()); assertNotNull(mergedConfig.getLocations()); assertArrayEquals(expectedLocations, mergedConfig.getLocations()); assertNotNull(mergedConfig.getClasses()); assertArrayEquals(expectedClasses, mergedConfig.getClasses()); assertNotNull(mergedConfig.getActiveProfiles()); if (expectedContextLoaderClass == null) { assertNull(mergedConfig.getContextLoader()); } else { assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass()); } assertNotNull(mergedConfig.getContextInitializerClasses()); assertEquals(expectedInitializerClasses, mergedConfig.getContextInitializerClasses()); }
@Test public void resolveContextHierarchyAttributesForSingleTestClassWithTripleLevelContextHierarchy() { Class<SingleTestClassWithTripleLevelContextHierarchy> testClass = SingleTestClassWithTripleLevelContextHierarchy.class; List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(testClass); assertEquals(1, hierarchyAttributes.size()); List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0); assertNotNull(configAttributesList); assertEquals(3, configAttributesList.size()); debugConfigAttributes(configAttributesList); assertAttributes(configAttributesList.get(0), testClass, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); assertAttributes(configAttributesList.get(1), testClass, new String[] { "B.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); assertAttributes(configAttributesList.get(2), testClass, new String[] { "C.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
/** * Returns {@link WebDelegatingSmartContextLoader} if the supplied class is * annotated with {@link WebAppConfiguration @WebAppConfiguration} and * otherwise delegates to the superclass. */ @Override protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) { if (AnnotationUtils.findAnnotation(testClass, WebAppConfiguration.class) != null) { return WebDelegatingSmartContextLoader.class; } // else... return super.getDefaultContextLoaderClass(testClass); }
@Test public void resolveConfigAttributesWithBareAnnotations() { Class<BareAnnotations> testClass = BareAnnotations.class; List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass); assertNotNull(attributesList); assertEquals(1, attributesList.size()); assertAttributes(attributesList.get(0), testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Test public void resolveConfigAttributesWithMetaAnnotationAndLocations() { Class<MetaLocationsFoo> testClass = MetaLocationsFoo.class; List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass); assertNotNull(attributesList); assertEquals(1, attributesList.size()); assertAttributes(attributesList.get(0), testClass, new String[] {"/foo.xml"}, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Test public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverrides() { Class<MetaLocationsFooWithOverrides> testClass = MetaLocationsFooWithOverrides.class; List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass); assertNotNull(attributesList); assertEquals(1, attributesList.size()); assertAttributes(attributesList.get(0), testClass, new String[] {"/foo.xml"}, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Test public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverriddenAttributes() { Class<MetaLocationsFooWithOverriddenAttributes> testClass = MetaLocationsFooWithOverriddenAttributes.class; List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass); assertNotNull(attributesList); assertEquals(1, attributesList.size()); assertAttributes(attributesList.get(0), testClass, new String[] {"foo1.xml", "foo2.xml"}, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Test public void resolveConfigAttributesWithMetaAnnotationAndLocationsInClassHierarchy() { Class<MetaLocationsBar> testClass = MetaLocationsBar.class; List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass); assertNotNull(attributesList); assertEquals(2, attributesList.size()); assertAttributes(attributesList.get(0), testClass, new String[] {"/bar.xml"}, EMPTY_CLASS_ARRAY, ContextLoader.class, true); assertAttributes(attributesList.get(1), MetaLocationsFoo.class, new String[] {"/foo.xml"}, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass, String[] expectedLocations, Class<?>[] expectedClasses, Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) { assertEquals("declaring class", expectedDeclaringClass, attributes.getDeclaringClass()); assertArrayEquals("locations", expectedLocations, attributes.getLocations()); assertArrayEquals("classes", expectedClasses, attributes.getClasses()); assertEquals("inherit locations", expectedInheritLocations, attributes.isInheritLocations()); assertEquals("context loader", expectedContextLoaderClass, attributes.getContextLoaderClass()); }
void assertMergedConfig(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass, String[] expectedLocations, Class<?>[] expectedClasses, Class<? extends ContextLoader> expectedContextLoaderClass) { assertMergedConfig(mergedConfig, expectedTestClass, expectedLocations, expectedClasses, EMPTY_INITIALIZER_CLASSES, expectedContextLoaderClass); }
@Test public void buildMergedConfigWithLocalAnnotationAndOverriddenContextLoaderAndLocations() { Class<?> testClass = PropertiesLocationsFoo.class; Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class; MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); assertMergedConfig(mergedConfig, testClass, new String[] { "classpath:/foo.properties" }, EMPTY_CLASS_ARRAY, expectedContextLoaderClass); }
@Test public void buildMergedConfigWithLocalAnnotationAndOverriddenContextLoaderAndClasses() { Class<?> testClass = PropertiesClassesFoo.class; Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class; MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass); assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, new Class<?>[] { FooConfig.class }, expectedContextLoaderClass); }
@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, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); loader.processContextConfiguration(configAttributes); assertEquals(1, configAttributes.getLocations().length); assertEmpty(configAttributes.getClasses()); }
@Test public void processContextConfigurationWithDefaultConfigurationClassGeneration() { ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(ConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); loader.processContextConfiguration(configAttributes); assertEquals(1, configAttributes.getClasses().length); assertEmpty(configAttributes.getLocations()); }
@Test public void processContextConfigurationWithDefaultXmlConfigAndConfigurationClassGeneration() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage(containsString("both default locations AND default configuration classes were detected")); ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); loader.processContextConfiguration(configAttributes); }
@Test public 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); assertArrayEquals(locations, configAttributes.getLocations()); assertEmpty(configAttributes.getClasses()); }
@Test public void processContextConfigurationWithConfigurationClass() { Class<?>[] classes = new Class<?>[] { getClass() }; ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(getClass(), EMPTY_STRING_ARRAY, classes, true, null, true, ContextLoader.class); loader.processContextConfiguration(configAttributes); assertArrayEquals(classes, configAttributes.getClasses()); assertEmpty(configAttributes.getLocations()); }
@Test public void resolveContextHierarchyAttributesForSingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation() { Class<SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation> testClass = SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation.class; List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(testClass); assertEquals(1, hierarchyAttributes.size()); List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0); assertNotNull(configAttributesList); assertEquals(1, configAttributesList.size()); debugConfigAttributes(configAttributesList); assertAttributes(configAttributesList.get(0), testClass, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Test public void resolveContextHierarchyAttributesForTestClassHierarchyWithSingleLevelContextHierarchiesAndMetaAnnotations() { List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation.class); assertEquals(3, hierarchyAttributes.size()); List<ContextConfigurationAttributes> configAttributesListClassLevel1 = hierarchyAttributes.get(0); debugConfigAttributes(configAttributesListClassLevel1); assertEquals(1, configAttributesListClassLevel1.size()); assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("A.xml")); assertAttributes(configAttributesListClassLevel1.get(0), TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation.class, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1); debugConfigAttributes(configAttributesListClassLevel2); assertEquals(1, configAttributesListClassLevel2.size()); assertArrayEquals(new String[] { "B-one.xml", "B-two.xml" }, configAttributesListClassLevel2.get(0).getLocations()); assertAttributes(configAttributesListClassLevel2.get(0), TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation.class, new String[] { "B-one.xml", "B-two.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); List<ContextConfigurationAttributes> configAttributesListClassLevel3 = hierarchyAttributes.get(2); debugConfigAttributes(configAttributesListClassLevel3); assertEquals(1, configAttributesListClassLevel3.size()); assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("C.xml")); assertAttributes(configAttributesListClassLevel3.get(0), TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation.class, new String[] { "C.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true); }
@Override protected ContextLoader resolveContextLoader(Class<?> testClass, List<ContextConfigurationAttributes> configAttributesList) { Class<?>[] classes = getClasses(testClass); if (!ObjectUtils.isEmpty(classes)) { for (ContextConfigurationAttributes configAttributes : configAttributesList) { addConfigAttributesClasses(configAttributes, classes); } } return super.resolveContextLoader(testClass, configAttributesList); }
@Override protected Class<? extends ContextLoader> getDefaultContextLoaderClass( Class<?> testClass) { if (AnnotationUtils.findAnnotation(testClass, WebIntegrationTest.class) != null) { return WebDelegatingSmartContextLoader.class; } return super.getDefaultContextLoaderClass(testClass); }
@Override protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) { if (AnnotationUtils.findAnnotation(testClass, RemockWebAppTest.class) != null) { return RemockContextClassLoader.WebApp.class; } return RemockContextClassLoader.Regular.class; }
@Test(expected = IllegalStateException.class) public void processContextConfigurationWithDefaultXmlConfigAndConfigurationClassGeneration() { ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes( ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, null, true, ContextLoader.class); loader.processContextConfiguration(configAttributes); }
/** * Returns {@link DelegatingSmartContextLoader}. */ @Override protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) { return DelegatingSmartContextLoader.class; }
/** * Build the {@link MergedContextConfiguration merged context configuration} * for the supplied {@link Class testClass}, context configuration attributes, * and parent context configuration. * @param testClass the test class for which the {@code MergedContextConfiguration} * should be built (must not be {@code null}) * @param configAttributesList the list of context configuration attributes for the * specified test class, ordered <em>bottom-up</em> (i.e., as if we were * traversing up the class hierarchy); never {@code null} or empty * @param parentConfig the merged context configuration for the parent application * 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 * @return the merged context configuration * @see #resolveContextLoader * @see ContextLoaderUtils#resolveContextConfigurationAttributes * @see SmartContextLoader#processContextConfiguration * @see ContextLoader#processLocations * @see ActiveProfilesUtils#resolveActiveProfiles * @see ApplicationContextInitializerUtils#resolveInitializerClasses * @see MergedContextConfiguration */ private MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass, List<ContextConfigurationAttributes> configAttributesList, MergedContextConfiguration parentConfig, CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) { ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList); List<String> locationsList = new ArrayList<String>(); List<Class<?>> classesList = new ArrayList<Class<?>>(); for (ContextConfigurationAttributes configAttributes : configAttributesList) { if (logger.isTraceEnabled()) { logger.trace(String.format("Processing locations and classes for context configuration attributes %s", configAttributes)); } 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())); } else { String[] processedLocations = contextLoader.processLocations(configAttributes.getDeclaringClass(), configAttributes.getLocations()); locationsList.addAll(0, Arrays.asList(processedLocations)); // Legacy ContextLoaders don't know how to process classes } if (!configAttributes.isInheritLocations()) { break; } } String[] locations = StringUtils.toStringArray(locationsList); Class<?>[] classes = ClassUtils.toClassArray(classesList); Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = // ApplicationContextInitializerUtils.resolveInitializerClasses(configAttributesList); String[] activeProfiles = ActiveProfilesUtils.resolveActiveProfiles(testClass); MergedTestPropertySources mergedTestPropertySources = TestPropertySourceUtils.buildMergedTestPropertySources(testClass); MergedContextConfiguration mergedConfig = new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles, mergedTestPropertySources.getLocations(), mergedTestPropertySources.getProperties(), contextLoader, cacheAwareContextLoaderDelegate, parentConfig); return processMergedContextConfiguration(mergedConfig); }
@Override protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) { return GenericPropertiesContextLoader.class; }
private void assertLocationsFooAttributes(ContextConfigurationAttributes attributes) { assertAttributes(attributes, LocationsFoo.class, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, false); }