Description
Geoff Metselaar opened SPR-5243 and commented
Status Quo
When the Spring TestContext Framework was introduced in Spring 2.5, it supported loading an ApplicationContext
from either XML or Java Properties files. Spring 3.1 introduced support for loading an ApplicationContext
from annotated classes (e.g., @Configuration
classes).
The underlying implementation for the existing support creates a GenericApplicationContext
; however, a GenericApplicationContext
is not suitable for testing a web application since a web application relies on an implementation of WebApplicationContext
(WAC).
In order to integration test Spring-powered web applications the Spring TestContext Framework needs to be able to load a WebApplicationContext
, either from XML configuration files or from annotated classes. Furthermore, the ServletContext
used by such a WAC needs to be configurable within tests, and common context hierarchies must be supported (e.g., root and dispatcher WACs in a parent-child relationship).
Original Author's Description
While writing some MVC integration tests, context errors were thrown when loading an XmlViewResolver
and when attempting to recover command object property validation errors using the RequestContext
. The reason is that each of these requires access to a WebApplicationContext
, not a GenericApplicationContext
which the TestContext framework makes available by default.
Goals
- Introduce an annotation that allows developers to configure a mock
ServletContext
from within integration tests. - Introduce
SmartContextLoaders
that can loadWebApplicationContexts
from either XML or annotated classes, using the configured mockServletContext
. - Provide a means for developers to access the mocks for the
HttpServletRequest
andHttpServletResponse
objects and ensure that thread-local state in Spring MVC is kept in sync with these mock objects. - Ensure that metadata used to create the
WebApplicationContext
(e.g.,ServletContext
path) is used to define the unique application context cache key.
Deliverables
- Implement a
SmartContextLoader
that loads aWebApplicationContext
from XML resource locations defined via@ContextConfiguration
- Implement a
SmartContextLoader
that loads aWebApplicationContext
from annotated classes defined via@ContextConfiguration
- Introduce a new class-level
@WebAppConfiguration
annotation that allows for configuration of theServletContext
base resource path, using Spring'sResource
abstraction- see
ContextMockMvcBuilder.configureWebAppRootDir()
fromspring-test-mvc
- the base path must be filesystem-based by default, in contrast to the
locations
attribute in@ContextConfiguration
which is classpath-based - the base path should default to "src/main/webapp", which follows the Maven convention
- determine if
@WebAppConfiguration
should be inherited (i.e., annotated with@Inherited
), keeping in mind that the top-level context in an EAR would not be a WAC
- see
- Ensure that the two newly introduced
SmartContextLoader
implementations create aMockServletContext
on demand (i.e., if a root WAC), when the WAC is loaded, and set theMockServletContext
as theServletContext
in the application contexts that they load - Set a loaded context as the
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
in theMockServletContext
when context hierarchies are not used - Introduce a subclass of
MergedContextConfiguration
specific for web apps (e.g.,WebMergedContextConfiguration
) that stores theServletContext
base path- the subclass of MCC must override
equals()
andhashCode()
to include the metadata that uniquely identifies the resulting WAC for proper context caching - the
buildMergedContextConfiguration()
method inContextLoaderUtils
will likely need to instantiate either a standardMergedContextConfiguration
or aWebMergedContextConfiguration
- the subclass of MCC must override
- Set up default thread local state via
RequestContextHolder
before each test method by implementing a new Servlet-specificTestExecutionListener
- by using the
MockServletContext
already present in the WAC and by creating aMockHttpServletRequest
,MockHttpServletResponse
, andServletWebRequest
which will be set in theRequestContextHolder
- by using the
- Ensure that the
MockServletContext
,MockHttpServletRequest
,MockHttpServletResponse
, andServletWebRequest
can be injected into the test instance (e.g., via@Autowired
) - Clean up thread locals after each test method
- Ensure that the Servlet-specific
TestExecutionListener
is configured as a defaultTestExecutionListener
beforeDependencyInjectionTestExecutionListener
- Introduce a new web-specific
DelegatingSmartContextLoader
to incorporate support for theSmartContextLoader
types introduced in this issue and ensure that the correct delegating loader is picked based on the presence or absence of@WebAppConfiguration
- Consider being able to accommodate a future request to support mocks for Spring Portlet MVC
Pseudocode Examples
Root WAC with Injected Mocks
@WebAppConfiguration // path defaults to "file:src/main/webapp"
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public class RootWacTests {
@Autowired
private WebApplicationContext wac;
@Autowired
private MockServletContext servletContext;
@Autowired
private MockHttpServletRequest request;
@Autowired
private MockHttpServletResponse response;
@Autowired
private MockHttpSession session;
@Autowired
private ServletWebRequest webRequest;
//...
}
Further Resources
Blogs and Custom Solutions
- http://codinghood.blogspot.com/2009/01/spring-integration-testing-for-web.html
- http://jamesfarrell129.wordpress.com/2011/04/20/integration-testing-for-spring-portlet-mvc/
- http://tedyoung.me/2011/02/14/spring-mvc-integration-testing-controllers/
- http://code.google.com/p/ted-young/source/browse/trunk/blog.spring-mvc-integration-testing/
Forum Discussions
- http://forum.springframework.org/showthread.php?p=210177#post210177
- http://forum.springframework.org/showthread.php?p=210181
- http://forum.springsource.org/showthread.php?t=76744
Affects: 2.5 final, 3.0 GA, 3.1 GA
Attachments:
- web_listener_loader.zip (6.70 kB)
Issue Links:
- Provide support for context hierarchies in the TestContext Framework [SPR-5613] #10284 Provide support for context hierarchies in the TestContext Framework ("depends on")
- Support WebApplicationContext hierarchies in the TestContext Framework [SPR-9863] #14496 Support WebApplicationContext hierarchies in the TestContext Framework ("is depended on by")
- Provide support for session/request scoped beans for integration testing [SPR-4588] #9265 Provide support for session/request scoped beans for integration testing ("is depended on by")
- Document WebApplicationContext support in the TestContext Framework [SPR-9864] #14497 Document WebApplicationContext support in the TestContext Framework ("is depended on by")
- Provide a ContextLoader for WebApplicationContext [SPR-5850] #10519 Provide a ContextLoader for WebApplicationContext ("is duplicated by")
- Provide test ContextLoader for @ContextConfiguration that creates a WebApplicationContext [SPR-5399] #10072 Provide test ContextLoader for
@ContextConfiguration
that creates a WebApplicationContext ("is duplicated by") - Make Spring ContextTest annotation support WebApplicationContext [SPR-4759] #9436 Make Spring ContextTest annotation support WebApplicationContext ("is duplicated by")
- Add first class support for testing Spring MVC applications [SPR-9859] #14492 Add first class support for testing Spring MVC applications
- Introduce bootstrap strategy in the TestContext framework [SPR-9955] #14588 Introduce bootstrap strategy in the TestContext framework
- Release 1.0 spring-test-mvc [SPR-9211] #13849 Release 1.0 spring-test-mvc
- ApplicationContext fails to load in tests using Java-based config and WebMvcConfigurationSupport [SPR-9799] #14432 ApplicationContext fails to load in tests using Java-based config and WebMvcConfigurationSupport ("supersedes")
Referenced from: commits 461d99a, a281bdb, 90c5f22, 9937f84, a73280c, 21ebbb9
30 votes, 29 watchers