Support loading WebApplicationContexts in the TCF

Prior to this commit, the Spring TestContext Framework only supported
loading an ApplicationContext in integration tests from either XML or
Java Properties files (since Spring 2.5), and Spring 3.1 introduced
support for loading an ApplicationContext in integration tests from
annotated classes (e.g., @Configuration classes). All of the
ContextLoader implementations used to provide this support load a
GenericApplicationContext. However, a GenericApplicationContext is not
suitable for testing a web application since a web application relies on
an implementation of WebApplicationContext (WAC).

This commit makes it possible to integration test Spring-powered web
applications by adding the following functionality to the Spring
TestContext Framework.

 - Introduced AbstractGenericWebContextLoader and two concrete
   subclasses:
   - XmlWebContextLoader
   - AnnotationConfigWebContextLoader

 - Pulled up prepareContext(context, mergedConfig) from
   AbstractGenericContextLoader into AbstractContextLoader to allow it
   to be shared across web and non-web context loaders.

 - Introduced AnnotationConfigContextLoaderUtils and refactored
   AnnotationConfigContextLoader accordingly. These utils are also used
   by AnnotationConfigWebContextLoader.

 - Introduced a new @WebAppConfiguration annotation to denote that the
   ApplicationContext loaded for a test should be a WAC and to configure
   the base resource path for the root directory of a web application.

 - Introduced WebMergedContextConfiguration which extends
   MergedContextConfiguration with support for a baseResourcePath for
   the root directory of a web application.

 - ContextLoaderUtils.buildMergedContextConfiguration() now builds a
   WebMergedContextConfiguration instead of a standard
   MergedContextConfiguration if @WebAppConfiguration is present on the
   test class.

 - Introduced a configureWebResources() method in
   AbstractGenericWebContextLoader that is responsible for creating a
   MockServletContext with a proper ResourceLoader for the
   resourceBasePath configured in the WebMergedContextConfiguration. The
   resulting mock ServletContext is set in the WAC, and the WAC is
   stored as the Root WAC in the ServletContext.

 - Introduced a WebTestExecutionListener that sets up default thread
   local state via RequestContextHolder before each test method by using
   the MockServletContext already present in the WAC and by creating a
   MockHttpServletRequest, MockHttpServletResponse, and
   ServletWebRequest that is set in the RequestContextHolder. WTEL also
   ensures that the MockHttpServletResponse and ServletWebRequest can be
   injected into the test instance (e.g., via @Autowired) and cleans up
   thread locals after each test method.

 - WebTestExecutionListener is configured as a default
   TestExecutionListener before DependencyInjectionTestExecutionListener

 - Extracted AbstractDelegatingSmartContextLoader from
   DelegatingSmartContextLoader and introduced a new
   WebDelegatingSmartContextLoader.

 - ContextLoaderUtils now selects the default delegating ContextLoader
   class name based on the presence of @WebAppConfiguration on the test
   class.

 - Tests in the spring-test-mvc module no longer use a custom
   ContextLoader to load a WebApplicationContext. Instead, they now
   rely on new core functionality provided in this commit.

Issue: SPR-5243
This commit is contained in:
Sam Brannen
2012-10-06 22:24:55 +02:00
parent 3552173b81
commit a73280ccc8
29 changed files with 1474 additions and 601 deletions

View File

@@ -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());
}

View File

@@ -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"));
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.test.context.ContextConfiguration;
/**
* @author Sam Brannen
* @since 3.2
*/
@ContextConfiguration
public class BasicXmlWacTests extends AbstractBasicWacTests {
@Test
public void fooBarAutowired() {
assertEquals("bar", foo);
}
}

View File

@@ -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 {
}