-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Description
Sam Brannen opened SPR-13211 and commented
Status Quo
As discussed in the referenced question on Stack Overflow, the combination of loading a WebApplicationContext with the Spring TestContext Framework and using the Spring MVC Test Framework results in two instances of MockHttpServletRequest being created.
ServletTestExecutionListener.setUpRequestContextIfNecessary()creates aMockHttpServletRequestand makes it available to theWebApplicationContextvia theRequestAttributesstored as a thread-local variable in theRequestContextHolder.- The mocked request is then injected into any session-scoped or request-scoped bean in the
WebApplicationContext(following standard Spring semantics for scoped beans) or into the test instance.
- The mocked request is then injected into any session-scoped or request-scoped bean in the
MockMvc.perform()creates anotherMockHttpServletRequest(viaMockHttpServletRequestBuilder.createServletRequest()).- This mocked request is the one that is eventually supplied to the
TestDispatcherServletinMockMvc.perform()(via theMockFilterChain).
- This mocked request is the one that is eventually supplied to the
The end result is that there are two mocked requests. Consequently, components that have the request injected into them (following scoped-proxy semantics) will interact with a request object that has nothing to do with the request configured via RequestBuilders (e.g., get(), post(), etc.) in Spring MVC Test.
NB: the above assumptions regarding interactions between mocked requests and session/request-scoped beans have not been fully confirmed, but in any case it is possible to have a MockHttpServletRequest injected into a test that is then not used by Spring MVC Test, which leads to confusing results. For example, request parameters configured in the mock request created by the ServletTestExecutionListener are not visible to controller methods invoked via Spring MVC Test.
Deliverables
TBD
Proposal
Initial analysis shows that modifying the createServletRequest() method in MockHttpServletRequestBuilder as follows could work. In fact, no side effects have been uncovered within Spring's test suite as a result of this change.
/**
* Create a {@link MockHttpServletRequest}.
* <p>If an instance of {@code MockHttpServletRequest} is available via
* the {@link RequestAttributes} bound to the current thread in
* {@link RequestContextHolder}, this method simply returns that instance.
* <p>Otherwise, this method creates a new {@code MockHttpServletRequest}
* based on the supplied {@link ServletContext}.
* <p>Can be overridden in subclasses.
* @see RequestContextHolder#getRequestAttributes()
* @see ServletRequestAttributes
*/
protected MockHttpServletRequest createServletRequest(ServletContext servletContext) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request instanceof MockHttpServletRequest) {
return (MockHttpServletRequest) request;
}
}
return new MockHttpServletRequest(servletContext);
}However, special care should be taken with regard to MockMultipartHttpServletRequestBuilder.createServletRequest() since it creates a MockMultipartHttpServletRequest instead of a MockHttpServletRequest. Furthermore, potential side effects for third-party add-ons (e.g., the upcoming support for HtmlUnit in Spring MVC Test (#17749)) must be taken into consideration as well.
Affects: 3.2 GA
Reference URL: http://stackoverflow.com/questions/30757044/autowired-httpservletrequest-in-spring-test-integration-tests
Issue Links:
- Populate RequestAttributes before invoking FilterChain in MockMvc [SPR-13217] #17808 Populate RequestAttributes before invoking FilterChain in MockMvc
- Add MockMvc HtmlUnit Integration [SPR-13158] #17749 Add MockMvc HtmlUnit Integration
- MockMvc.perform with the TestContext framework causes additional perform invocations to be "polluted" [SPR-13260] #17851 MockMvc.perform with the TestContext framework causes additional perform invocations to be "polluted"
Referenced from: commits 5e24ee9, 3c799e6, bf06bf3, 3c2efee
0 votes, 5 watchers