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).
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.
- Introduce an annotation that allows developers to configure a mock ServletContext from within integration tests.
- Introduce SmartContextLoaders that can load WebApplicationContexts from either XML or annotated classes, using the configured mock ServletContext.
- Provide a means for developers to access the mocks for the HttpServletRequest and HttpServletResponse 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.
- Implement a SmartContextLoader that loads a WebApplicationContext from XML resource locations defined via @ContextConfiguration
- Implement a SmartContextLoader that loads a WebApplicationContext from annotated classes defined via @ContextConfiguration
- Introduce a new class-level @WebAppConfiguration annotation that allows for configuration of the ServletContext base resource path, using Spring's Resource abstraction
- see ContextMockMvcBuilder.configureWebAppRootDir() from spring-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
- Ensure that the two newly introduced SmartContextLoader implementations create a MockServletContext on demand (i.e., if a root WAC), when the WAC is loaded, and set the MockServletContext as the ServletContext in the application contexts that they load
- Set a loaded context as the ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE in the MockServletContext when context hierarchies are not used
- Introduce a subclass of MergedContextConfiguration specific for web apps (e.g., WebMergedContextConfiguration) that stores the ServletContext base path
- the subclass of MCC must override equals() and hashCode() to include the metadata that uniquely identifies the resulting WAC for proper context caching
- the buildMergedContextConfiguration() method in ContextLoaderUtils will likely need to instantiate either a standard MergedContextConfiguration or a WebMergedContextConfiguration
- Set up default thread local state via RequestContextHolder before each test method by implementing a new Servlet-specific TestExecutionListener
- by using the MockServletContext already present in the WAC and by creating a MockHttpServletRequest, MockHttpServletResponse, and ServletWebRequest which will be set in the RequestContextHolder
- Ensure that the MockServletContext, MockHttpServletRequest, MockHttpServletResponse, and ServletWebRequest 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 default TestExecutionListener before DependencyInjectionTestExecutionListener
- Introduce a new web-specific DelegatingSmartContextLoader to incorporate support for the SmartContextLoader 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