Merge pull request #160 from sbrannen/SPR-5243
Support loading WebApplicationContexts in the TCF
This commit is contained in:
commit
9937f840d5
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web.mock.servlet.samples.context;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.mock.web.MockRequestDispatcher;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.support.AbstractContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
/**
|
||||
* This class is here temporarily until the TestContext framework provides
|
||||
* support for WebApplicationContext yet:
|
||||
*
|
||||
* https://jira.springsource.org/browse/SPR-5243
|
||||
*
|
||||
* <p>After that this class will no longer be needed. It's provided here as an example
|
||||
* and to serve as a temporary solution.
|
||||
*/
|
||||
public class GenericWebContextLoader extends AbstractContextLoader {
|
||||
protected final MockServletContext servletContext;
|
||||
|
||||
public GenericWebContextLoader(String warRootDir, boolean isClasspathRelative) {
|
||||
ResourceLoader resourceLoader = isClasspathRelative ? new DefaultResourceLoader() : new FileSystemResourceLoader();
|
||||
this.servletContext = initServletContext(warRootDir, resourceLoader);
|
||||
}
|
||||
|
||||
private MockServletContext initServletContext(String warRootDir, ResourceLoader resourceLoader) {
|
||||
return new MockServletContext(warRootDir, resourceLoader) {
|
||||
// Required for DefaultServletHttpRequestHandler...
|
||||
public RequestDispatcher getNamedDispatcher(String path) {
|
||||
return (path.equals("default")) ? new MockRequestDispatcher(path) : super.getNamedDispatcher(path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
||||
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
||||
prepareContext(context);
|
||||
loadBeanDefinitions(context, mergedConfig);
|
||||
return context;
|
||||
}
|
||||
|
||||
public ApplicationContext loadContext(String... locations) throws Exception {
|
||||
// should never be called
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected void prepareContext(GenericWebApplicationContext context) {
|
||||
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
||||
context.setServletContext(this.servletContext);
|
||||
}
|
||||
|
||||
protected void loadBeanDefinitions(GenericWebApplicationContext context, String[] locations) {
|
||||
new XmlBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
context.refresh();
|
||||
context.registerShutdownHook();
|
||||
}
|
||||
|
||||
protected void loadBeanDefinitions(GenericWebApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
new AnnotatedBeanDefinitionReader(context).register(mergedConfig.getClasses());
|
||||
loadBeanDefinitions(context, mergedConfig.getLocations());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getResourceSuffix() {
|
||||
return "-context.xml";
|
||||
}
|
||||
}
|
||||
|
|
@ -16,9 +16,8 @@
|
|||
|
||||
package org.springframework.test.web.mock.servlet.samples.context;
|
||||
|
||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -26,21 +25,20 @@ import org.junit.runner.RunWith;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests with Java configuration.
|
||||
*
|
||||
* The TestContext framework doesn't support WebApplicationContext yet:
|
||||
* https://jira.springsource.org/browse/SPR-5243
|
||||
*
|
||||
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(loader=WebContextLoader.class, classes={WebConfig.class})
|
||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||
@ContextConfiguration(classes = WebConfig.class)
|
||||
public class JavaTestContextTests {
|
||||
|
||||
@Autowired
|
||||
|
|
@ -48,6 +46,7 @@ public class JavaTestContextTests {
|
|||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
|
|
@ -55,9 +54,9 @@ public class JavaTestContextTests {
|
|||
|
||||
@Test
|
||||
public void tilesDefinitions() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
this.mockMvc.perform(get("/"))//
|
||||
.andExpect(status().isOk())//
|
||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* 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.web.mock.servlet.samples.context;
|
||||
|
||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
|
@ -34,6 +35,7 @@ import org.springframework.security.web.FilterChainProxy;
|
|||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||
import org.springframework.test.web.mock.servlet.MvcResult;
|
||||
import org.springframework.test.web.mock.servlet.ResultMatcher;
|
||||
|
|
@ -44,32 +46,25 @@ import org.springframework.web.context.WebApplicationContext;
|
|||
/**
|
||||
* Basic example that includes Spring Security configuration.
|
||||
*
|
||||
* <p>Note that currently there are no {@link ResultMatcher}' built specifically
|
||||
* for asserting the Spring Security context. However, it's quite easy to put
|
||||
* them together as shown below and Spring Security extensions will become
|
||||
* available in the near future.
|
||||
* <p>Note that currently there are no {@linkplain ResultMatcher ResultMatchers}
|
||||
* built specifically for asserting the Spring Security context. However, it's
|
||||
* quite easy to put them together as shown below, and Spring Security extensions
|
||||
* will become available in the near future.
|
||||
*
|
||||
* <p>This also demonstrates a custom {@link RequestPostProcessor} which authenticates
|
||||
* a user to a particular {@link HttpServletRequest}.
|
||||
*
|
||||
* <p>Also see the Javadoc of {@link GenericWebContextLoader}, a class that
|
||||
* provides temporary support for loading WebApplicationContext by extending
|
||||
* the TestContext framework.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @see SecurityRequestPostProcessors
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(
|
||||
loader=WebContextLoader.class,
|
||||
value={
|
||||
"classpath:org/springframework/test/web/mock/servlet/samples/context/security.xml",
|
||||
"classpath:org/springframework/test/web/mock/servlet/samples/servlet-context.xml"
|
||||
})
|
||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||
@ContextConfiguration({ "security.xml", "../servlet-context.xml" })
|
||||
public class SpringSecurityTests {
|
||||
|
||||
private static String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
|
||||
private static final String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
|
||||
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain;
|
||||
|
|
@ -79,57 +74,67 @@ public class SpringSecurityTests {
|
|||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
|
||||
.addFilters(this.springSecurityFilterChain).build();
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)//
|
||||
.addFilters(this.springSecurityFilterChain)//
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresAuthentication() throws Exception {
|
||||
mockMvc.perform(get("/user"))
|
||||
.andExpect(redirectedUrl("http://localhost/spring_security_login"));
|
||||
mockMvc.perform(get("/user")).//
|
||||
andExpect(redirectedUrl("http://localhost/spring_security_login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessGranted() throws Exception {
|
||||
this.mockMvc.perform(get("/").with(userDeatilsService("user")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
this.mockMvc.perform(get("/").//
|
||||
with(userDeatilsService("user"))).//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessDenied() throws Exception {
|
||||
this.mockMvc.perform(get("/").with(user("user").roles("DENIED")))
|
||||
.andExpect(status().isForbidden());
|
||||
this.mockMvc.perform(get("/")//
|
||||
.with(user("user").roles("DENIED")))//
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userAuthenticates() throws Exception {
|
||||
final String username = "user";
|
||||
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "password"))
|
||||
.andExpect(redirectedUrl("/"))
|
||||
.andExpect(new ResultMatcher() {
|
||||
public void match(MvcResult mvcResult) throws Exception {
|
||||
HttpSession session = mvcResult.getRequest().getSession();
|
||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||
Assert.assertEquals(securityContext.getAuthentication().getName(), username);
|
||||
}
|
||||
});
|
||||
mockMvc.perform(post("/j_spring_security_check").//
|
||||
param("j_username", username).//
|
||||
param("j_password", "password")).//
|
||||
andExpect(redirectedUrl("/")).//
|
||||
andExpect(new ResultMatcher() {
|
||||
|
||||
public void match(MvcResult mvcResult) throws Exception {
|
||||
HttpSession session = mvcResult.getRequest().getSession();
|
||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||
Assert.assertEquals(securityContext.getAuthentication().getName(), username);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userAuthenticateFails() throws Exception {
|
||||
final String username = "user";
|
||||
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "invalid"))
|
||||
.andExpect(redirectedUrl("/spring_security_login?login_error"))
|
||||
.andExpect(new ResultMatcher() {
|
||||
public void match(MvcResult mvcResult) throws Exception {
|
||||
HttpSession session = mvcResult.getRequest().getSession();
|
||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||
Assert.assertNull(securityContext);
|
||||
}
|
||||
});
|
||||
mockMvc.perform(post("/j_spring_security_check").//
|
||||
param("j_username", username).//
|
||||
param("j_password", "invalid")).//
|
||||
andExpect(redirectedUrl("/spring_security_login?login_error")).//
|
||||
andExpect(new ResultMatcher() {
|
||||
|
||||
public void match(MvcResult mvcResult) throws Exception {
|
||||
HttpSession session = mvcResult.getRequest().getSession();
|
||||
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
|
||||
Assert.assertNull(securityContext);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@
|
|||
|
||||
package org.springframework.test.web.mock.servlet.samples.context;
|
||||
|
||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -26,23 +25,20 @@ import org.junit.runner.RunWith;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.mock.servlet.MockMvc;
|
||||
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests with XML configuration.
|
||||
*
|
||||
* The TestContext framework doesn't support WebApplicationContext yet:
|
||||
* https://jira.springsource.org/browse/SPR-5243
|
||||
*
|
||||
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(
|
||||
loader=WebContextLoader.class,
|
||||
locations={"/org/springframework/test/web/mock/servlet/samples/servlet-context.xml"})
|
||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||
@ContextConfiguration("../servlet-context.xml")
|
||||
public class XmlTestContextTests {
|
||||
|
||||
@Autowired
|
||||
|
|
@ -50,6 +46,7 @@ public class XmlTestContextTests {
|
|||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
|
|
@ -57,10 +54,9 @@ public class XmlTestContextTests {
|
|||
|
||||
@Test
|
||||
public void tilesDefinitions() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
this.mockMvc.perform(get("/"))//
|
||||
.andExpect(status().isOk())//
|
||||
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<configs>
|
||||
<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
|
||||
<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
|
||||
<config>src/test/resources/org/springframework/test/context/web/BasicXmlWacTests-config.xml</config>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import static org.springframework.beans.BeanUtils.instantiateClass;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass;
|
||||
import static org.springframework.beans.BeanUtils.*;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -30,6 +30,8 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -54,6 +56,7 @@ abstract class ContextLoaderUtils {
|
|||
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
|
||||
|
||||
private static final String DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.DelegatingSmartContextLoader";
|
||||
private static final String DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.WebDelegatingSmartContextLoader";
|
||||
|
||||
|
||||
private ContextLoaderUtils() {
|
||||
|
|
@ -83,7 +86,8 @@ abstract class ContextLoaderUtils {
|
|||
Assert.notNull(testClass, "Test class must not be null");
|
||||
|
||||
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
||||
defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||
defaultContextLoaderClassName = testClass.isAnnotationPresent(WebAppConfiguration.class) ? DEFAULT_WEB_CONTEXT_LOADER_CLASS_NAME
|
||||
: DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||
}
|
||||
|
||||
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
|
||||
|
|
@ -394,6 +398,14 @@ abstract class ContextLoaderUtils {
|
|||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = resolveInitializerClasses(configAttributesList);
|
||||
String[] activeProfiles = resolveActiveProfiles(testClass);
|
||||
|
||||
if (testClass.isAnnotationPresent(WebAppConfiguration.class)) {
|
||||
WebAppConfiguration webAppConfig = testClass.getAnnotation(WebAppConfiguration.class);
|
||||
String resourceBasePath = webAppConfig.value();
|
||||
return new WebMergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
|
||||
resourceBasePath, contextLoader);
|
||||
}
|
||||
|
||||
// else
|
||||
return new MergedContextConfiguration(testClass, locations, classes, initializerClasses, activeProfiles,
|
||||
contextLoader);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public class MergedContextConfiguration implements Serializable {
|
|||
* {@link ContextLoader} based solely on the fully qualified name of the
|
||||
* loader or "null" if the supplied loaded is <code>null</code>.
|
||||
*/
|
||||
private static String nullSafeToString(ContextLoader contextLoader) {
|
||||
protected static String nullSafeToString(ContextLoader contextLoader) {
|
||||
return contextLoader == null ? "null" : contextLoader.getClass().getName();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
*/
|
||||
private ApplicationContext loadApplicationContext() throws Exception {
|
||||
ContextLoader contextLoader = mergedContextConfiguration.getContextLoader();
|
||||
Assert.notNull(contextLoader, "Can not load an ApplicationContext with a NULL 'contextLoader'. "
|
||||
Assert.notNull(contextLoader, "Cannot load an ApplicationContext with a NULL 'contextLoader'. "
|
||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||
|
||||
ApplicationContext applicationContext;
|
||||
|
|
@ -125,7 +125,7 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
}
|
||||
else {
|
||||
String[] locations = mergedContextConfiguration.getLocations();
|
||||
Assert.notNull(locations, "Can not load an ApplicationContext with a NULL 'locations' array. "
|
||||
Assert.notNull(locations, "Cannot load an ApplicationContext with a NULL 'locations' array. "
|
||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||
applicationContext = contextLoader.loadContext(locations);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ import org.springframework.util.ObjectUtils;
|
|||
public class TestContextManager {
|
||||
|
||||
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
|
||||
"org.springframework.test.context.web.WebTestExecutionListener",
|
||||
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
||||
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
|
||||
|
|
@ -126,7 +127,6 @@ public class TestContextManager {
|
|||
return this.testContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the supplied {@link TestExecutionListener TestExecutionListeners}
|
||||
* by appending them to the set of listeners used by this <code>TestContextManager</code>.
|
||||
|
|
@ -155,8 +155,8 @@ public class TestContextManager {
|
|||
* registered for this <code>TestContextManager</code> in reverse order.
|
||||
*/
|
||||
private List<TestExecutionListener> getReversedTestExecutionListeners() {
|
||||
List<TestExecutionListener> listenersReversed =
|
||||
new ArrayList<TestExecutionListener>(getTestExecutionListeners());
|
||||
List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
|
||||
getTestExecutionListeners());
|
||||
Collections.reverse(listenersReversed);
|
||||
return listenersReversed;
|
||||
}
|
||||
|
|
@ -186,8 +186,7 @@ public class TestContextManager {
|
|||
}
|
||||
classesList.addAll(getDefaultTestExecutionListenerClasses());
|
||||
defaultListeners = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Traverse the class hierarchy...
|
||||
while (declaringClass != null) {
|
||||
TestExecutionListeners testExecutionListeners = declaringClass.getAnnotation(annotationType);
|
||||
|
|
@ -200,22 +199,21 @@ public class TestContextManager {
|
|||
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
|
||||
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
|
||||
String msg = String.format(
|
||||
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] " +
|
||||
"and 'listeners' [%s] attributes. Use one or the other, but not both.",
|
||||
"Test class [%s] has been configured with @TestExecutionListeners' 'value' [%s] "
|
||||
+ "and 'listeners' [%s] attributes. Use one or the other, but not both.",
|
||||
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
|
||||
ObjectUtils.nullSafeToString(listenerClasses));
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
|
||||
} else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
|
||||
listenerClasses = valueListenerClasses;
|
||||
}
|
||||
|
||||
if (listenerClasses != null) {
|
||||
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
|
||||
}
|
||||
declaringClass = (testExecutionListeners.inheritListeners() ?
|
||||
AnnotationUtils.findAnnotationDeclaringClass(annotationType, declaringClass.getSuperclass()) : null);
|
||||
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass()) : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,16 +221,14 @@ public class TestContextManager {
|
|||
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
|
||||
try {
|
||||
listeners.add(BeanUtils.instantiateClass(listenerClass));
|
||||
}
|
||||
catch (NoClassDefFoundError err) {
|
||||
} catch (NoClassDefFoundError err) {
|
||||
if (defaultListeners) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not instantiate default TestExecutionListener class ["
|
||||
+ listenerClass.getName()
|
||||
+ "]. Specify custom listener classes or make the default listener classes available.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
|
@ -245,24 +241,21 @@ public class TestContextManager {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() {
|
||||
Set<Class<? extends TestExecutionListener>> defaultListenerClasses =
|
||||
new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
||||
Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<Class<? extends TestExecutionListener>>();
|
||||
for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) {
|
||||
try {
|
||||
defaultListenerClasses.add(
|
||||
(Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(
|
||||
className));
|
||||
} catch (Throwable t) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not load default TestExecutionListener class [" + className
|
||||
+ "]. Specify custom listener classes or make the default listener classes available.");
|
||||
+ "]. Specify custom listener classes or make the default listener classes available.", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultListenerClasses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hook for pre-processing a test class <em>before</em> execution of any
|
||||
* tests within the class. Should be called prior to any framework-specific
|
||||
|
|
@ -286,8 +279,7 @@ public class TestContextManager {
|
|||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.beforeTestClass(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'before class' callback for test class [" + testClass + "]", ex);
|
||||
throw ex;
|
||||
|
|
@ -319,8 +311,7 @@ public class TestContextManager {
|
|||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.prepareTestInstance(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
logger.error("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to prepare test instance [" + testInstance + "]", ex);
|
||||
throw ex;
|
||||
|
|
@ -356,8 +347,7 @@ public class TestContextManager {
|
|||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.beforeTestMethod(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'before' execution of test method [" + testMethod + "] for test instance ["
|
||||
+ testInstance + "]", ex);
|
||||
|
|
@ -404,8 +394,7 @@ public class TestContextManager {
|
|||
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.afterTestMethod(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'after' execution for test: method [" + testMethod + "], instance ["
|
||||
+ testInstance + "], exception [" + exception + "]", ex);
|
||||
|
|
@ -446,8 +435,7 @@ public class TestContextManager {
|
|||
for (TestExecutionListener testExecutionListener : getReversedTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.afterTestClass(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'after class' callback for test class [" + testClass + "]", ex);
|
||||
if (afterTestClassException == null) {
|
||||
|
|
|
|||
|
|
@ -16,13 +16,24 @@
|
|||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
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.ClassUtils;
|
||||
|
|
@ -81,6 +92,64 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
|||
configAttributes.setLocations(processedLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the {@link ConfigurableApplicationContext} created by this
|
||||
* {@code SmartContextLoader} <i>before</i> bean definitions are read.
|
||||
*
|
||||
* <p>The default implementation:
|
||||
* <ul>
|
||||
* <li>Sets the <em>active bean definition profiles</em> from the supplied
|
||||
* <code>MergedContextConfiguration</code> in the
|
||||
* {@link org.springframework.core.env.Environment Environment} of the context.</li>
|
||||
* <li>Determines what (if any) context initializer classes have been supplied
|
||||
* via the {@code MergedContextConfiguration} and
|
||||
* {@linkplain ApplicationContextInitializer#initialize invokes each} with the
|
||||
* given application context.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Any {@code ApplicationContextInitializers} implementing
|
||||
* {@link org.springframework.core.Ordered Ordered} or marked with {@link
|
||||
* org.springframework.core.annotation.Order @Order} will be sorted appropriately.
|
||||
*
|
||||
* @param context the newly created application context
|
||||
* @param mergedConfig the merged context configuration
|
||||
* @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @see ConfigurableApplicationContext#setId
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
|
||||
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
||||
|
||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
|
||||
|
||||
if (initializerClasses.size() == 0) {
|
||||
// no ApplicationContextInitializers have been declared -> nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||
final Class<?> contextClass = context.getClass();
|
||||
|
||||
for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
||||
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
|
||||
ApplicationContextInitializer.class);
|
||||
Assert.isAssignable(initializerContextClass, contextClass, String.format(
|
||||
"Could not add context initializer [%s] since its generic parameter [%s] "
|
||||
+ "is not assignable from the type of application context used by this "
|
||||
+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
||||
contextClass.getName()));
|
||||
initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
|
||||
}
|
||||
|
||||
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
|
||||
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
|
||||
initializer.initialize(context);
|
||||
}
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
|
@ -185,12 +254,10 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
|||
String path = locations[i];
|
||||
if (path.startsWith(SLASH)) {
|
||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||
}
|
||||
else if (!ResourcePatternUtils.isUrl(path)) {
|
||||
} else if (!ResourcePatternUtils.isUrl(path)) {
|
||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
|
||||
+ StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
modifiedLocations[i] = StringUtils.cleanPath(path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
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
|
||||
* for implementations of the {@link SmartContextLoader} SPI that delegate to a
|
||||
* set of <em>candidate</em> SmartContextLoaders (i.e., one that supports XML
|
||||
* configuration files and one that supports annotated classes) to determine which
|
||||
* context loader is appropriate for a given test class's configuration. Each
|
||||
* candidate is given a chance to {@link #processContextConfiguration process} the
|
||||
* {@link ContextConfigurationAttributes} for each class in the test class hierarchy
|
||||
* that is annotated with {@link ContextConfiguration @ContextConfiguration}, and
|
||||
* the candidate that supports the merged, processed configuration will be used to
|
||||
* actually {@link #loadContext load} the context.
|
||||
*
|
||||
* <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
|
||||
* that default resource locations (i.e., XML configuration files) or default
|
||||
* {@link org.springframework.context.annotation.Configuration configuration classes}
|
||||
* should be detected. Furthermore, if a specific {@link ContextLoader} or
|
||||
* {@link SmartContextLoader} is not explicitly declared via
|
||||
* {@code @ContextConfiguration}, a concrete subclass of
|
||||
* {@code AbstractDelegatingSmartContextLoader} will be used as the default loader,
|
||||
* thus providing automatic support for either XML configuration files or annotated
|
||||
* classes, but not both simultaneously.
|
||||
*
|
||||
* <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
|
||||
* files nor annotated classes and instead declare only {@linkplain
|
||||
* ContextConfiguration#initializers application context initializers}. In such
|
||||
* cases, an attempt will still be made to detect defaults, but their absence will
|
||||
* not result an an exception.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
* @see SmartContextLoader
|
||||
*/
|
||||
abstract class AbstractDelegatingSmartContextLoader implements SmartContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractDelegatingSmartContextLoader.class);
|
||||
|
||||
|
||||
/**
|
||||
* Get the delegate {@code SmartContextLoader} that supports XML configuration files.
|
||||
*/
|
||||
protected abstract SmartContextLoader getXmlLoader();
|
||||
|
||||
/**
|
||||
* Get the delegate {@code SmartContextLoader} that supports annotated classes.
|
||||
*/
|
||||
protected abstract SmartContextLoader getAnnotationConfigLoader();
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
private static String name(SmartContextLoader loader) {
|
||||
return loader.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
|
||||
configAttributes));
|
||||
}
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
|
||||
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
||||
}
|
||||
return loader.loadContext(mergedConfig);
|
||||
}
|
||||
|
||||
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||
if (loader == getAnnotationConfigLoader()) {
|
||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
} else {
|
||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
|
||||
* {@link ContextConfigurationAttributes}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||
* delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations or annotated classes in the supplied
|
||||
* {@code ContextConfigurationAttributes} are not empty, the appropriate
|
||||
* candidate loader will be allowed to process the configuration <em>as is</em>,
|
||||
* without any checks for detection of defaults.</li>
|
||||
* <li>Otherwise, the XML-based loader will be allowed to process
|
||||
* the configuration in order to detect default resource locations. If
|
||||
* the XML-based loader detects default resource locations,
|
||||
* an {@code info} message will be logged.</li>
|
||||
* <li>Subsequently, the annotation-based loader will be allowed to
|
||||
* process the configuration in order to detect default configuration classes.
|
||||
* If the annotation-based loader detects default configuration
|
||||
* classes, an {@code info} message will be logged.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @throws IllegalArgumentException if the supplied configuration attributes are
|
||||
* <code>null</code>, or if the supplied configuration attributes include both
|
||||
* resource locations and annotated classes
|
||||
* @throws IllegalStateException if the XML-based loader detects default
|
||||
* configuration classes; if the annotation-based loader detects default
|
||||
* resource locations; if neither candidate loader detects defaults for the supplied
|
||||
* context configuration; or if both candidate loaders detect defaults for the
|
||||
* supplied context configuration
|
||||
*/
|
||||
public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
|
||||
|
||||
Assert.notNull(configAttributes, "configAttributes must not be null");
|
||||
Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
|
||||
"Cannot process locations AND classes for context "
|
||||
+ "configuration %s; configure one or the other, but not both.", configAttributes));
|
||||
|
||||
// If the original locations or classes were not empty, there's no
|
||||
// need to bother with default detection checks; just let the
|
||||
// appropriate loader process the configuration.
|
||||
if (configAttributes.hasLocations()) {
|
||||
delegateProcessing(getXmlLoader(), configAttributes);
|
||||
} else if (configAttributes.hasClasses()) {
|
||||
delegateProcessing(getAnnotationConfigLoader(), configAttributes);
|
||||
} else {
|
||||
// Else attempt to detect defaults...
|
||||
|
||||
// Let the XML loader process the configuration.
|
||||
delegateProcessing(getXmlLoader(), configAttributes);
|
||||
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
|
||||
|
||||
if (xmlLoaderDetectedDefaults) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("%s detected default locations for context configuration %s.",
|
||||
name(getXmlLoader()), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if (configAttributes.hasClasses()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default configuration classes for context configuration %s.",
|
||||
name(getXmlLoader()), configAttributes));
|
||||
}
|
||||
|
||||
// Now let the annotation config loader process the configuration.
|
||||
delegateProcessing(getAnnotationConfigLoader(), configAttributes);
|
||||
|
||||
if (configAttributes.hasClasses()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format(
|
||||
"%s detected default configuration classes for context configuration %s.",
|
||||
name(getAnnotationConfigLoader()), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default locations for context configuration %s.",
|
||||
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 "
|
||||
+ "were detected for context configuration %s; configure one or the other, but not both.",
|
||||
configAttributes);
|
||||
logger.error(message);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||
* an {@link ApplicationContext}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||
* delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations in the supplied {@code MergedContextConfiguration}
|
||||
* are not empty and the annotated classes are empty,
|
||||
* the XML-based loader will load the {@code ApplicationContext}.</li>
|
||||
* <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
|
||||
* are not empty and the resource locations are empty,
|
||||
* the annotation-based loader will load the {@code ApplicationContext}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param mergedConfig the merged context configuration to use to load the application context
|
||||
* @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
|
||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||
* {@code ApplicationContext} from the supplied merged context configuration
|
||||
*/
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||
|
||||
List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader());
|
||||
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// If neither of the candidates supports the mergedConfig based on resources but
|
||||
// ACIs were declared, then delegate to the annotation config loader.
|
||||
if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
|
||||
return delegateLoading(getAnnotationConfigLoader(), mergedConfig);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format(
|
||||
"Neither %s nor %s was able to load an ApplicationContext from %s.", name(getXmlLoader()),
|
||||
name(getAnnotationConfigLoader()), mergedConfig));
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* {@code AbstractDelegatingSmartContextLoader} does not support the
|
||||
* {@link ContextLoader#processLocations(Class, String...)} method. Call
|
||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public final String[] processLocations(Class<?> clazz, String... locations) {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code AbstractDelegatingSmartContextLoader} does not support the
|
||||
* {@link ContextLoader#loadContext(String...) } method. Call
|
||||
* {@link #loadContext(MergedContextConfiguration)} instead.
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public final ApplicationContext loadContext(String... locations) throws Exception {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||
+ "Call loadContext(MergedContextConfiguration) instead.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,25 +16,14 @@
|
|||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +66,10 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
*
|
||||
* <ul>
|
||||
* <li>Creates a {@link GenericApplicationContext} instance.</li>
|
||||
* <li>Calls {@link #prepareContext(GenericApplicationContext, MergedContextConfiguration)}
|
||||
* <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
|
||||
* compatibility with the {@link org.springframework.test.context.ContextLoader
|
||||
* ContextLoader} SPI.</li>
|
||||
* <li>Calls {@link #prepareContext(ConfigurableApplicationContext, MergedContextConfiguration)}
|
||||
* to allow for customizing the context before bean definitions are loaded.</li>
|
||||
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to allow for customizing the
|
||||
* context's <code>DefaultListableBeanFactory</code>.</li>
|
||||
|
|
@ -105,6 +97,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
}
|
||||
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
prepareContext(context);
|
||||
prepareContext(context, mergedConfig);
|
||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||
loadBeanDefinitions(context, mergedConfig);
|
||||
|
|
@ -183,72 +176,6 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
protected void prepareContext(GenericApplicationContext context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the {@link GenericApplicationContext} created by this
|
||||
* {@code SmartContextLoader} <i>before</i> bean definitions are read.
|
||||
*
|
||||
* <p>The default implementation:
|
||||
* <ul>
|
||||
* <li>Calls {@link #prepareContext(GenericApplicationContext)} for backwards
|
||||
* compatibility with the {@link org.springframework.test.context.ContextLoader
|
||||
* ContextLoader} SPI.</li>
|
||||
* <li>Sets the <em>active bean definition profiles</em> from the supplied
|
||||
* <code>MergedContextConfiguration</code> in the
|
||||
* {@link org.springframework.core.env.Environment Environment} of the context.</li>
|
||||
* <li>Determines what (if any) context initializer classes have been supplied
|
||||
* via the {@code MergedContextConfiguration} and
|
||||
* {@linkplain ApplicationContextInitializer#initialize invokes each} with the
|
||||
* given application context.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Any {@code ApplicationContextInitializers} implementing
|
||||
* {@link org.springframework.core.Ordered Ordered} or marked with {@link
|
||||
* org.springframework.core.annotation.Order @Order} will be sorted appropriately.
|
||||
*
|
||||
* @param applicationContext the newly created application context
|
||||
* @param mergedConfig the merged context configuration
|
||||
* @see ApplicationContextInitializer#initialize(GenericApplicationContext)
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
|
||||
* @see GenericApplicationContext#setResourceLoader
|
||||
* @see GenericApplicationContext#setId
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void prepareContext(GenericApplicationContext applicationContext,
|
||||
MergedContextConfiguration mergedConfig) {
|
||||
|
||||
prepareContext(applicationContext);
|
||||
|
||||
applicationContext.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
||||
|
||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
|
||||
|
||||
if (initializerClasses.size() == 0) {
|
||||
// no ApplicationContextInitializers have been declared -> nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
final List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||
final Class<?> contextClass = applicationContext.getClass();
|
||||
|
||||
for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
||||
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
|
||||
ApplicationContextInitializer.class);
|
||||
Assert.isAssignable(initializerContextClass, contextClass, String.format(
|
||||
"Could not add context initializer [%s] since its generic parameter [%s] "
|
||||
+ "is not assignable from the type of application context used by this "
|
||||
+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
||||
contextClass.getName()));
|
||||
initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
|
||||
}
|
||||
|
||||
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
|
||||
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
|
||||
initializer.initialize(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the internal bean factory of the ApplicationContext created by
|
||||
* this <code>ContextLoader</code>.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document AbstractGenericWebContextLoader.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
public abstract class AbstractGenericWebContextLoader extends AbstractContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractGenericWebContextLoader.class);
|
||||
|
||||
|
||||
// --- SmartContextLoader -----------------------------------------------
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden loadContext(MergedContextConfiguration).
|
||||
*
|
||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(org.springframework.test.context.MergedContextConfiguration)
|
||||
*/
|
||||
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
|
||||
if (!(mergedConfig instanceof WebMergedContextConfiguration)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Cannot load WebApplicationContext from non-web merged context configuration %s. "
|
||||
+ "Consider annotating your test class with @WebAppConfiguration.", mergedConfig));
|
||||
}
|
||||
WebMergedContextConfiguration webMergedConfig = (WebMergedContextConfiguration) mergedConfig;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Loading WebApplicationContext for merged context configuration %s.",
|
||||
webMergedConfig));
|
||||
}
|
||||
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
||||
configureWebResources(context, webMergedConfig);
|
||||
prepareContext(context, webMergedConfig);
|
||||
customizeBeanFactory(context.getDefaultListableBeanFactory(), webMergedConfig);
|
||||
loadBeanDefinitions(context, webMergedConfig);
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
customizeContext(context, webMergedConfig);
|
||||
context.refresh();
|
||||
context.registerShutdownHook();
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document configureWebResources().
|
||||
*/
|
||||
protected void configureWebResources(GenericWebApplicationContext context,
|
||||
WebMergedContextConfiguration webMergedConfig) {
|
||||
|
||||
String resourceBasePath = webMergedConfig.getResourceBasePath();
|
||||
ResourceLoader resourceLoader = resourceBasePath.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX) ? new DefaultResourceLoader()
|
||||
: new FileSystemResourceLoader();
|
||||
|
||||
ServletContext servletContext = new MockServletContext(resourceBasePath, resourceLoader);
|
||||
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
||||
context.setServletContext(servletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document customizeBeanFactory().
|
||||
*/
|
||||
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory,
|
||||
WebMergedContextConfiguration webMergedConfig) {
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document loadBeanDefinitions().
|
||||
*/
|
||||
protected abstract void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||
WebMergedContextConfiguration webMergedConfig);
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document customizeContext().
|
||||
*/
|
||||
protected void customizeContext(GenericWebApplicationContext context, WebMergedContextConfiguration webMergedConfig) {
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden loadContext(String...).
|
||||
*
|
||||
* @see org.springframework.test.context.ContextLoader#loadContext(java.lang.String[])
|
||||
*/
|
||||
public final ApplicationContext loadContext(String... locations) throws Exception {
|
||||
throw new UnsupportedOperationException(
|
||||
"AbstractGenericWebContextLoader does not support the loadContext(String... locations) method");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,19 +16,13 @@
|
|||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -89,80 +83,19 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
|||
|
||||
// --- AnnotationConfigContextLoader ---------------------------------------
|
||||
|
||||
private boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
int modifiers = clazz.getModifiers();
|
||||
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Class} meets the criteria for being
|
||||
* considered a <em>default configuration class</em> candidate.
|
||||
*
|
||||
* <p>Specifically, such candidates:
|
||||
*
|
||||
* <ul>
|
||||
* <li>must not be <code>null</code></li>
|
||||
* <li>must not be <code>private</code></li>
|
||||
* <li>must not be <code>final</code></li>
|
||||
* <li>must be <code>static</code></li>
|
||||
* <li>must be annotated with {@code @Configuration}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param clazz the class to check
|
||||
* @return <code>true</code> if the supplied class meets the candidate criteria
|
||||
*/
|
||||
private boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the default configuration classes for the supplied test class.
|
||||
*
|
||||
* <p>The returned class array will contain all static inner classes of
|
||||
* the supplied class that meet the requirements for {@code @Configuration}
|
||||
* class implementations as specified in the documentation for
|
||||
* {@link Configuration @Configuration}.
|
||||
* <p>The default implementation simply delegates to
|
||||
* {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
|
||||
*
|
||||
* <p>The implementation of this method adheres to the contract defined in the
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||
* SPI. Specifically, this method uses introspection to detect default
|
||||
* configuration classes that comply with the constraints required of
|
||||
* {@code @Configuration} class implementations. If a potential candidate
|
||||
* configuration class does not meet these requirements, this method will log a
|
||||
* warning, and the potential candidate class will be ignored.
|
||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||
* @return an array of default configuration classes, potentially empty but
|
||||
* never <code>null</code>
|
||||
* @see AnnotationConfigContextLoaderUtils
|
||||
*/
|
||||
protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||
Assert.notNull(declaringClass, "Declaring class must not be null");
|
||||
|
||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||
|
||||
for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
|
||||
if (isDefaultConfigurationClassCandidate(candidate)) {
|
||||
configClasses.add(candidate);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
|
||||
+ "with @Configuration to be considered a default configuration class.",
|
||||
candidate.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configClasses.isEmpty()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
|
||||
+ "%s does not declare any static, non-private, non-final, inner classes "
|
||||
+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
return configClasses.toArray(new Class<?>[configClasses.size()]);
|
||||
return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
|
||||
}
|
||||
|
||||
// --- AbstractContextLoader -----------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document AnnotationConfigContextLoaderUtils.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
abstract class AnnotationConfigContextLoaderUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoaderUtils.class);
|
||||
|
||||
|
||||
private AnnotationConfigContextLoaderUtils() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
int modifiers = clazz.getModifiers();
|
||||
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Class} meets the criteria for being
|
||||
* considered a <em>default configuration class</em> candidate.
|
||||
*
|
||||
* <p>Specifically, such candidates:
|
||||
*
|
||||
* <ul>
|
||||
* <li>must not be <code>null</code></li>
|
||||
* <li>must not be <code>private</code></li>
|
||||
* <li>must not be <code>final</code></li>
|
||||
* <li>must be <code>static</code></li>
|
||||
* <li>must be annotated with {@code @Configuration}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param clazz the class to check
|
||||
* @return <code>true</code> if the supplied class meets the candidate criteria
|
||||
*/
|
||||
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the default configuration classes for the supplied test class.
|
||||
*
|
||||
* <p>The returned class array will contain all static inner classes of
|
||||
* the supplied class that meet the requirements for {@code @Configuration}
|
||||
* class implementations as specified in the documentation for
|
||||
* {@link Configuration @Configuration}.
|
||||
*
|
||||
* <p>The implementation of this method adheres to the contract defined in the
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||
* SPI. Specifically, this method uses introspection to detect default
|
||||
* configuration classes that comply with the constraints required of
|
||||
* {@code @Configuration} class implementations. If a potential candidate
|
||||
* configuration class does not meet these requirements, this method will log a
|
||||
* warning, and the potential candidate class will be ignored.
|
||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||
* @return an array of default configuration classes, potentially empty but
|
||||
* never <code>null</code>
|
||||
*/
|
||||
static Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||
Assert.notNull(declaringClass, "Declaring class must not be null");
|
||||
|
||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||
|
||||
for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
|
||||
if (isDefaultConfigurationClassCandidate(candidate)) {
|
||||
configClasses.add(candidate);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
|
||||
+ "with @Configuration to be considered a default configuration class.",
|
||||
candidate.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configClasses.isEmpty()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
|
||||
+ "%s does not declare any static, non-private, non-final, inner classes "
|
||||
+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
return configClasses.toArray(new Class<?>[configClasses.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document AnnotationConfigWebContextLoader.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AnnotationConfigWebContextLoader extends AbstractGenericWebContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AnnotationConfigWebContextLoader.class);
|
||||
|
||||
|
||||
// --- SmartContextLoader -----------------------------------------------
|
||||
|
||||
/**
|
||||
* Process <em>annotated classes</em> in the supplied {@link ContextConfigurationAttributes}.
|
||||
*
|
||||
* <p>If the <em>annotated classes</em> are <code>null</code> or empty and
|
||||
* {@link #isGenerateDefaultLocations()} returns <code>true</code>, this
|
||||
* <code>SmartContextLoader</code> will attempt to {@link
|
||||
* #detectDefaultConfigurationClasses detect default configuration classes}.
|
||||
* If defaults are detected they will be
|
||||
* {@link ContextConfigurationAttributes#setClasses(Class[]) set} in the
|
||||
* supplied configuration attributes. Otherwise, properties in the supplied
|
||||
* configuration attributes will not be modified.
|
||||
*
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @see org.springframework.test.context.SmartContextLoader#processContextConfiguration(ContextConfigurationAttributes)
|
||||
* @see #isGenerateDefaultLocations()
|
||||
* @see #detectDefaultConfigurationClasses(Class)
|
||||
*/
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && isGenerateDefaultLocations()) {
|
||||
Class<?>[] defaultConfigClasses = detectDefaultConfigurationClasses(configAttributes.getDeclaringClass());
|
||||
configAttributes.setClasses(defaultConfigClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the default configuration classes for the supplied test class.
|
||||
*
|
||||
* <p>The default implementation simply delegates to
|
||||
* {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses(Class)}.
|
||||
*
|
||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||
* @return an array of default configuration classes, potentially empty but
|
||||
* never <code>null</code>
|
||||
* @see AnnotationConfigContextLoaderUtils
|
||||
*/
|
||||
protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||
return AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);
|
||||
}
|
||||
|
||||
// --- AbstractContextLoader -----------------------------------------------
|
||||
|
||||
/**
|
||||
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||
* Consequently, this method is not supported.
|
||||
*
|
||||
* @see AbstractContextLoader#modifyLocations
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
@Override
|
||||
protected String[] modifyLocations(Class<?> clazz, String... locations) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigWebContextLoader does not support the modifyLocations(Class, String...) method");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||
* Consequently, this method is not supported.
|
||||
*
|
||||
* @see AbstractContextLoader#generateDefaultLocations
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
@Override
|
||||
protected String[] generateDefaultLocations(Class<?> clazz) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigWebContextLoader does not support the generateDefaultLocations(Class) method");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code AnnotationConfigWebContextLoader} should be used as a
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
|
||||
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
|
||||
* Consequently, this method is not supported.
|
||||
*
|
||||
* @see AbstractContextLoader#getResourceSuffix
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
@Override
|
||||
protected String getResourceSuffix() {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigWebContextLoader does not support the getResourceSuffix() method");
|
||||
}
|
||||
|
||||
// --- AbstractGenericWebContextLoader -------------------------------------
|
||||
|
||||
/**
|
||||
* Register classes in the supplied {@link GenericWebApplicationContext context}
|
||||
* from the classes in the supplied {@link WebMergedContextConfiguration}.
|
||||
*
|
||||
* <p>Each class must represent an <em>annotated class</em>. An
|
||||
* {@link AnnotatedBeanDefinitionReader} is used to register the appropriate
|
||||
* bean definitions.
|
||||
*
|
||||
* @param context the context in which the annotated classes should be registered
|
||||
* @param webMergedConfig the merged configuration from which the classes should be retrieved
|
||||
*
|
||||
* @see AbstractGenericWebContextLoader#loadBeanDefinitions
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||
WebMergedContextConfiguration webMergedConfig) {
|
||||
Class<?>[] annotatedClasses = webMergedConfig.getClasses();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering annotated classes: " + ObjectUtils.nullSafeToString(annotatedClasses));
|
||||
}
|
||||
new AnnotatedBeanDefinitionReader(context).register(annotatedClasses);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,263 +16,32 @@
|
|||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
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 DelegatingSmartContextLoader} is an implementation of the {@link SmartContextLoader}
|
||||
* SPI that delegates to a set of <em>candidate</em> SmartContextLoaders (i.e.,
|
||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}) to
|
||||
* determine which context loader is appropriate for a given test class's configuration.
|
||||
* Each candidate is given a chance to {@link #processContextConfiguration process} the
|
||||
* {@link ContextConfigurationAttributes} for each class in the test class hierarchy that
|
||||
* is annotated with {@link ContextConfiguration @ContextConfiguration}, and the candidate
|
||||
* that supports the merged, processed configuration will be used to actually
|
||||
* {@link #loadContext load} the context.
|
||||
*
|
||||
* <p>Placing an empty {@code @ContextConfiguration} annotation on a test class signals
|
||||
* that default resource locations (i.e., XML configuration files) or default
|
||||
* {@link org.springframework.context.annotation.Configuration configuration classes}
|
||||
* should be detected. Furthermore, if a specific {@link ContextLoader} or
|
||||
* {@link SmartContextLoader} is not explicitly declared via
|
||||
* {@code @ContextConfiguration}, {@code DelegatingSmartContextLoader} will be used as
|
||||
* the default loader, thus providing automatic support for either XML configuration
|
||||
* files or annotated classes, but not both simultaneously.
|
||||
*
|
||||
* <p>As of Spring 3.2, a test class may optionally declare neither XML configuration
|
||||
* files nor annotated classes and instead declare only {@linkplain
|
||||
* ContextConfiguration#initializers application context initializers}. In such
|
||||
* cases, an attempt will still be made to detect defaults, but their absence will
|
||||
* not result an an exception.
|
||||
* {@code DelegatingSmartContextLoader} is a concrete implementation of
|
||||
* {@link AbstractDelegatingSmartContextLoader} that delegates to a
|
||||
* {@link GenericXmlContextLoader} and an {@link AnnotationConfigContextLoader}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see SmartContextLoader
|
||||
* @see AbstractDelegatingSmartContextLoader
|
||||
* @see GenericXmlContextLoader
|
||||
* @see AnnotationConfigContextLoader
|
||||
*/
|
||||
public class DelegatingSmartContextLoader implements SmartContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DelegatingSmartContextLoader.class);
|
||||
public class DelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
|
||||
|
||||
private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
|
||||
private final SmartContextLoader annotationConfigLoader = new AnnotationConfigContextLoader();
|
||||
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
private static String name(SmartContextLoader loader) {
|
||||
return loader.getClass().getSimpleName();
|
||||
protected SmartContextLoader getXmlLoader() {
|
||||
return this.xmlLoader;
|
||||
}
|
||||
|
||||
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to process context configuration %s.", name(loader),
|
||||
configAttributes));
|
||||
}
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
|
||||
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
||||
}
|
||||
return loader.loadContext(mergedConfig);
|
||||
}
|
||||
|
||||
private static boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||
if (loader instanceof AnnotationConfigContextLoader) {
|
||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
} else {
|
||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
|
||||
* {@link ContextConfigurationAttributes}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of
|
||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
|
||||
* Specifically, the delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations or annotated classes in the supplied
|
||||
* {@code ContextConfigurationAttributes} are not empty, the appropriate
|
||||
* candidate loader will be allowed to process the configuration <em>as is</em>,
|
||||
* without any checks for detection of defaults.</li>
|
||||
* <li>Otherwise, {@code GenericXmlContextLoader} will be allowed to process
|
||||
* the configuration in order to detect default resource locations. If
|
||||
* {@code GenericXmlContextLoader} detects default resource locations,
|
||||
* an {@code info} message will be logged.</li>
|
||||
* <li>Subsequently, {@code AnnotationConfigContextLoader} will be allowed to
|
||||
* process the configuration in order to detect default configuration classes.
|
||||
* If {@code AnnotationConfigContextLoader} detects default configuration
|
||||
* classes, an {@code info} message will be logged.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @throws IllegalArgumentException if the supplied configuration attributes are
|
||||
* <code>null</code>, or if the supplied configuration attributes include both
|
||||
* resource locations and annotated classes
|
||||
* @throws IllegalStateException if {@code GenericXmlContextLoader} detects default
|
||||
* configuration classes; if {@code AnnotationConfigContextLoader} detects default
|
||||
* resource locations; if neither candidate loader detects defaults for the supplied
|
||||
* context configuration; or if both candidate loaders detect defaults for the
|
||||
* supplied context configuration
|
||||
*/
|
||||
public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
|
||||
|
||||
Assert.notNull(configAttributes, "configAttributes must not be null");
|
||||
Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
|
||||
"Cannot process locations AND classes for context "
|
||||
+ "configuration %s; configure one or the other, but not both.", configAttributes));
|
||||
|
||||
// If the original locations or classes were not empty, there's no
|
||||
// need to bother with default detection checks; just let the
|
||||
// appropriate loader process the configuration.
|
||||
if (configAttributes.hasLocations()) {
|
||||
delegateProcessing(xmlLoader, configAttributes);
|
||||
} else if (configAttributes.hasClasses()) {
|
||||
delegateProcessing(annotationConfigLoader, configAttributes);
|
||||
} else {
|
||||
// Else attempt to detect defaults...
|
||||
|
||||
// Let the XML loader process the configuration.
|
||||
delegateProcessing(xmlLoader, configAttributes);
|
||||
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
|
||||
|
||||
if (xmlLoaderDetectedDefaults) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("%s detected default locations for context configuration %s.",
|
||||
name(xmlLoader), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if (configAttributes.hasClasses()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default configuration classes for context configuration %s.",
|
||||
name(xmlLoader), configAttributes));
|
||||
}
|
||||
|
||||
// Now let the annotation config loader process the configuration.
|
||||
delegateProcessing(annotationConfigLoader, configAttributes);
|
||||
|
||||
if (configAttributes.hasClasses()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format(
|
||||
"%s detected default configuration classes for context configuration %s.",
|
||||
name(annotationConfigLoader), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default locations for context configuration %s.",
|
||||
name(annotationConfigLoader), 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(xmlLoader),
|
||||
name(annotationConfigLoader), configAttributes));
|
||||
}
|
||||
|
||||
if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
|
||||
String message = String.format(
|
||||
"Configuration error: both default locations AND default configuration classes "
|
||||
+ "were detected for context configuration %s; configure one or the other, but not both.",
|
||||
configAttributes);
|
||||
logger.error(message);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||
* an {@link ApplicationContext}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of
|
||||
* {@link GenericXmlContextLoader} and {@link AnnotationConfigContextLoader}.
|
||||
* Specifically, the delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations in the supplied {@code MergedContextConfiguration}
|
||||
* are not empty and the annotated classes are empty,
|
||||
* {@code GenericXmlContextLoader} will load the {@code ApplicationContext}.</li>
|
||||
* <li>If the annotated classes in the supplied {@code MergedContextConfiguration}
|
||||
* are not empty and the resource locations are empty,
|
||||
* {@code AnnotationConfigContextLoader} will load the {@code ApplicationContext}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param mergedConfig the merged context configuration to use to load the application context
|
||||
* @throws IllegalArgumentException if the supplied merged configuration is <code>null</code>
|
||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||
* {@code ApplicationContext} from the supplied merged context configuration
|
||||
*/
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||
|
||||
List<SmartContextLoader> candidates = Arrays.asList(xmlLoader, annotationConfigLoader);
|
||||
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// If neither of the candidates supports the mergedConfig based on resources but
|
||||
// ACIs were declared, then delegate to the ACCL.
|
||||
if (!mergedConfig.getContextInitializerClasses().isEmpty()) {
|
||||
return delegateLoading(annotationConfigLoader, mergedConfig);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format(
|
||||
"Neither %s nor %s was able to load an ApplicationContext from %s.", name(xmlLoader),
|
||||
name(annotationConfigLoader), mergedConfig));
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* {@code DelegatingSmartContextLoader} does not support the
|
||||
* {@link ContextLoader#processLocations(Class, String...)} method. Call
|
||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)} instead.
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public String[] processLocations(Class<?> clazz, String... locations) {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
|
||||
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code DelegatingSmartContextLoader} does not support the
|
||||
* {@link ContextLoader#loadContext(String...) } method. Call
|
||||
* {@link #loadContext(MergedContextConfiguration)} instead.
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public ApplicationContext loadContext(String... locations) throws Exception {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoader does not support the ContextLoader SPI. "
|
||||
+ "Call loadContext(MergedContextConfiguration) instead.");
|
||||
protected SmartContextLoader getAnnotationConfigLoader() {
|
||||
return this.annotationConfigLoader;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
|
||||
/**
|
||||
* {@code WebDelegatingSmartContextLoader} is a concrete implementation of
|
||||
* {@link AbstractDelegatingSmartContextLoader} that delegates to an
|
||||
* {@link XmlWebContextLoader} and an {@link AnnotationConfigWebContextLoader}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
* @see SmartContextLoader
|
||||
* @see AbstractDelegatingSmartContextLoader
|
||||
* @see XmlWebContextLoader
|
||||
* @see AnnotationConfigWebContextLoader
|
||||
*/
|
||||
public class WebDelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
|
||||
|
||||
private final SmartContextLoader xmlLoader = new XmlWebContextLoader();
|
||||
private final SmartContextLoader annotationConfigLoader = new AnnotationConfigWebContextLoader();
|
||||
|
||||
|
||||
protected SmartContextLoader getXmlLoader() {
|
||||
return this.xmlLoader;
|
||||
}
|
||||
|
||||
protected SmartContextLoader getAnnotationConfigLoader() {
|
||||
return this.annotationConfigLoader;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.support;
|
||||
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document XmlWebContextLoader.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
public class XmlWebContextLoader extends AbstractGenericWebContextLoader {
|
||||
|
||||
/**
|
||||
* Returns "<code>-context.xml</code>".
|
||||
*/
|
||||
protected String getResourceSuffix() {
|
||||
return "-context.xml";
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden loadBeanDefinitions().
|
||||
*
|
||||
* @see org.springframework.test.context.support.AbstractGenericWebContextLoader#loadBeanDefinitions(org.springframework.web.context.support.GenericWebApplicationContext, org.springframework.test.context.web.WebMergedContextConfiguration)
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(GenericWebApplicationContext context,
|
||||
WebMergedContextConfiguration webMergedConfig) {
|
||||
new XmlBeanDefinitionReader(context).loadBeanDefinitions(webMergedConfig.getLocations());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document WebAppConfiguration.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface WebAppConfiguration {
|
||||
|
||||
/**
|
||||
* The root directory of the web application (i.e., WAR); should not end with a slash.
|
||||
*
|
||||
* <p>Defaults to {@code "src/main/webapp"}.
|
||||
*/
|
||||
String value() default "src/main/webapp";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document WebMergedContextConfiguration.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
public class WebMergedContextConfiguration extends MergedContextConfiguration {
|
||||
|
||||
private static final long serialVersionUID = 7323361588604247458L;
|
||||
|
||||
private final String resourceBasePath;
|
||||
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document WebMergedContextConfiguration constructor.
|
||||
*/
|
||||
public WebMergedContextConfiguration(
|
||||
Class<?> testClass,
|
||||
String[] locations,
|
||||
Class<?>[] classes,
|
||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses,
|
||||
String[] activeProfiles, String resourceBasePath, ContextLoader contextLoader) {
|
||||
|
||||
super(testClass, locations, classes, contextInitializerClasses, activeProfiles, contextLoader);
|
||||
|
||||
this.resourceBasePath = !StringUtils.hasText(resourceBasePath) ? "" : resourceBasePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document getResourceBasePath().
|
||||
*/
|
||||
public String getResourceBasePath() {
|
||||
return this.resourceBasePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique hash code for all properties of this
|
||||
* {@code WebMergedContextConfiguration} excluding the
|
||||
* {@linkplain #getTestClass() test class}.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + resourceBasePath.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied object is equal to this {@code WebMergedContextConfiguration}
|
||||
* instance by comparing both object's {@linkplain #getLocations() locations},
|
||||
* {@linkplain #getClasses() annotated classes},
|
||||
* {@linkplain #getContextInitializerClasses() context initializer classes},
|
||||
* {@linkplain #getActiveProfiles() active profiles},
|
||||
* {@linkplain #getResourceBasePath() resource base path}, and the fully
|
||||
* qualified names of their {@link #getContextLoader() ContextLoaders}.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof WebMergedContextConfiguration)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final WebMergedContextConfiguration that = (WebMergedContextConfiguration) obj;
|
||||
|
||||
return super.equals(that) && this.getResourceBasePath().equals(that.getResourceBasePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a String representation of the {@linkplain #getTestClass() test class},
|
||||
* {@linkplain #getLocations() locations}, {@linkplain #getClasses() annotated classes},
|
||||
* {@linkplain #getContextInitializerClasses() context initializer classes},
|
||||
* {@linkplain #getActiveProfiles() active profiles},
|
||||
* {@linkplain #getResourceBasePath() resource base path}, and the name of the
|
||||
* {@link #getContextLoader() ContextLoader}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)//
|
||||
.append("testClass", getTestClass())//
|
||||
.append("locations", ObjectUtils.nullSafeToString(getLocations()))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(getClasses()))//
|
||||
.append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses()))//
|
||||
.append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles()))//
|
||||
.append("resourceBasePath", getResourceBasePath())//
|
||||
.append("contextLoader", nullSafeToString(getContextLoader()))//
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document WebTestExecutionListener.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
public class WebTestExecutionListener extends AbstractTestExecutionListener {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(WebTestExecutionListener.class);
|
||||
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden prepareTestInstance().
|
||||
*
|
||||
* @see org.springframework.test.context.support.AbstractTestExecutionListener#prepareTestInstance(org.springframework.test.context.TestContext)
|
||||
*/
|
||||
@Override
|
||||
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||
setUpRequestContextIfNecessary(testContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden beforeTestMethod().
|
||||
*
|
||||
* @see org.springframework.test.context.support.AbstractTestExecutionListener#beforeTestMethod(org.springframework.test.context.TestContext)
|
||||
*/
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
setUpRequestContextIfNecessary(testContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document setUpRequestContext().
|
||||
*
|
||||
* @param testContext
|
||||
* @param servletContext
|
||||
*/
|
||||
private void setUpRequestContextIfNecessary(TestContext testContext) {
|
||||
|
||||
ApplicationContext context = testContext.getApplicationContext();
|
||||
|
||||
if (context instanceof WebApplicationContext) {
|
||||
WebApplicationContext wac = (WebApplicationContext) context;
|
||||
ServletContext servletContext = wac.getServletContext();
|
||||
if (!(servletContext instanceof MockServletContext)) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"The WebApplicationContext for test context %s must be configured with a MockServletContext.",
|
||||
testContext));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.",
|
||||
testContext));
|
||||
}
|
||||
|
||||
if (RequestContextHolder.getRequestAttributes() == null) {
|
||||
MockServletContext mockServletContext = (MockServletContext) servletContext;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);
|
||||
|
||||
RequestContextHolder.setRequestAttributes(servletWebRequest);
|
||||
|
||||
if (wac instanceof ConfigurableApplicationContext) {
|
||||
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) wac;
|
||||
ConfigurableListableBeanFactory bf = configurableApplicationContext.getBeanFactory();
|
||||
bf.registerResolvableDependency(MockHttpServletResponse.class, response);
|
||||
bf.registerResolvableDependency(ServletWebRequest.class, servletWebRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO [SPR-5243] Document overridden afterTestMethod().
|
||||
*
|
||||
* @see org.springframework.test.context.support.AbstractTestExecutionListener#afterTestMethod(org.springframework.test.context.TestContext)
|
||||
*/
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
|
||||
}
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -42,7 +42,7 @@ public class TestExecutionListenersTests {
|
|||
@Test
|
||||
public void verifyNumDefaultListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 3,
|
||||
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 4,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
/**
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
public abstract class AbstractBasicWacTests implements ServletContextAware {
|
||||
|
||||
protected ServletContext servletContext;
|
||||
|
||||
@Autowired
|
||||
protected WebApplicationContext wac;
|
||||
|
||||
@Autowired
|
||||
protected MockServletContext mockServletContext;
|
||||
|
||||
@Autowired
|
||||
protected MockHttpServletRequest request;
|
||||
|
||||
@Autowired
|
||||
protected MockHttpServletResponse response;
|
||||
|
||||
@Autowired
|
||||
protected ServletWebRequest webRequest;
|
||||
|
||||
@Autowired
|
||||
protected String foo;
|
||||
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicWacFeatures() throws Exception {
|
||||
assertNotNull("ServletContext should be set in the WAC.", wac.getServletContext());
|
||||
|
||||
assertNotNull("ServletContext should have been set via ServletContextAware.", servletContext);
|
||||
|
||||
assertNotNull("ServletContext should have been autowired from the WAC.", mockServletContext);
|
||||
assertNotNull("MockHttpServletRequest should have been autowired from the WAC.", request);
|
||||
assertNotNull("MockHttpServletResponse should have been autowired from the WAC.", response);
|
||||
assertNotNull("ServletWebRequest should have been autowired from the WAC.", webRequest);
|
||||
|
||||
Object rootWac = mockServletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
assertNotNull("Root WAC must be stored in the ServletContext as: "
|
||||
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWac);
|
||||
assertSame("test WAC and Root WAC in ServletContext must be the same object.", wac, rootWac);
|
||||
assertSame("ServletContext instances must be the same object.", mockServletContext, wac.getServletContext());
|
||||
assertSame("ServletContext in the WAC and in the mock request", mockServletContext, request.getServletContext());
|
||||
|
||||
assertEquals("Getting real path for ServletContext resource.",
|
||||
new File("src/main/webapp/index.jsp").getCanonicalPath(), mockServletContext.getRealPath("index.jsp"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public class BasicAnnotationConfigWacTests extends AbstractBasicWacTests {
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "enigma";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void fooEnigmaAutowired() {
|
||||
assertEquals("enigma", foo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,12 +13,24 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.mock.servlet.samples.context;
|
||||
|
||||
class WebContextLoader extends GenericWebContextLoader {
|
||||
package org.springframework.test.context.web;
|
||||
|
||||
public WebContextLoader() {
|
||||
super("src/test/resources/META-INF/web-resources", false);
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public class BasicXmlWacTests extends AbstractBasicWacTests {
|
||||
|
||||
@Test
|
||||
public void fooBarAutowired() {
|
||||
assertEquals("bar", foo);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Convenience test suite for integration tests that verify support for
|
||||
* {@link WebApplicationContext} {@linkplain ContextLoader context loaders}
|
||||
* in the TestContext framework.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
// Note: the following 'multi-line' layout is for enhanced code readability.
|
||||
@SuiteClasses({//
|
||||
BasicXmlWacTests.class,//
|
||||
BasicAnnotationConfigWacTests.class //
|
||||
})
|
||||
public class WebContextLoaderTestSuite {
|
||||
}
|
||||
|
|
@ -45,6 +45,10 @@
|
|||
<level value="warn" />
|
||||
</logger>
|
||||
|
||||
<logger name="org.springframework.test.context.web">
|
||||
<level value="warn" />
|
||||
</logger>
|
||||
|
||||
<logger name="org.springframework.test.context">
|
||||
<level value="warn" />
|
||||
</logger>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="foo" class="java.lang.String" c:_="bar" />
|
||||
|
||||
</beans>
|
||||
Loading…
Reference in New Issue