Rob Winch opened SPR-13818 and commented
Status Quo
The MockMvc
support provides an excellent API for testing Spring MVC applications. However, there are users that leverage Spring that may not be using Spring MVC. For example, Spring Security users do not necessarily use Spring MVC.
Without a dedicated API users are forced to manually apply things like RequestPostProcessor
, ResultActions
, ResultMatchers
, etc. Not everything from the MockMvc
support can be extracted out, but much of it can.
Proposal
It would be nice if an API that was not dependent on Spring MVC were extracted from MockMvc
. A possible name might be MockHttp
.
Issue Links: - #19647 MockMvc compatible API for doing real HTTP tests - #18393 Provide MockMvc support for Stateful HttpSession
0 votes, 7 watchers
Comment From: spring-projects-issues
Juergen Hoeller commented
I'd rather have this scheduled for 5.0...
Rossen Stoyanchev, what's your take on this?
Juergen
Comment From: spring-projects-issues
Rossen Stoyanchev commented
Definitely a 5.0. It would be easy to plug any Servlet. That said Spring MVC is in many of the core contracts, anything that takes MvcResult
for example. So it might be a little tricky in terms of backwards compatibility. Generally I agree with the description but I'm wondering is there anything specific to motivate this?
Comment From: spring-projects-issues
Rob Winch commented
Thanks for cleaning up the issue Sam Brannen. I did not intend to log this as a bug.
Juergen Hoeller Thanks for the response. I think that a 5.0 candidate would be fine.
That said Spring MVC is in many of the core contracts, anything that takes MvcResult for example. So it might be a little tricky in terms of backwards compatibility
Rossen Stoyanchev I haven't put a lot of thought into this yet, so perhaps you are seeing a problem that I am not. My initial thought was that we would extract an interface that contained the common methods and then make MvcResult
extend it. Perhaps something like this:
public interface HttpResult {
MockHttpServletRequest getRequest();
MockHttpServletResponse getResponse();
}
public interface MvcResult extends HttpResult {
Object getHandler();
HandlerInterceptor[] getInterceptors();
ModelAndView getModelAndView();
Exception getResolvedException();
FlashMap getFlashMap();
Object getAsyncResult();
Object getAsyncResult(long timeToWait);
}
Generally I agree with the description but I'm wondering is there anything specific to motivate this?
The reason is that I have had lots of users ask how to use the Spring Security Test support without Spring MVC. This can work in a limited scope, but is far from ideal. For example, if I want to include a valid CSRF token within a request I can do something like this:
MockHttpServletRequest request = ...;
request = csrf().postProcess(request);
However..
- Users need to be certain that the
MockHttpServletRequest
passed in contains theFilterChainProxy
reference (either in aWebApplicationContext
or a Servlet attribute) - It will not function properly if they modify the request after it was post processed. This is because the setup of CSRF token depends on the final value of the
HttpServletRequest
(since users can map security differently based on theHttpServletRequest
). - Finally, there is no easy way to say for every
MockHttpServletRequest
in a set of tests to include a CSRF token.
There are many other pieces of Spring Security's MockMvc
integration that would be valuable when users do not use Spring MVC. For example, I love that run a test within MockMvc
as a particular user as shown below:
@WithMockUser
public void run() {
mockMvc.perform(get("/"));
}
This isn't easy when using the FilterChainProxy
directly because Spring Security's SecurityContextPersistenceFilter
will clear out the SecurityContext
that was setup unless it finds a SecurityContext
in the HttpServletRequest
. We could do something similar to what we demonstrated for CSRF, but we suffer from all the same setbacks.
I happen to be rewriting lots of the Spring Security tests at the moment and find this feature would be appreciated there as well. At the moment I work around the problem by using a stand alone setup with a controller that does nothing. This works for me because I already have an optional Spring MVC dependency, but might not be ideal for users that do not otherwise use Spring MVC.
Comment From: spring-projects-issues
Rossen Stoyanchev commented
The reason is that I have had lots of users ask how to use the Spring Security Test support without Spring MVC.
Okay thanks for the extra detail. I wonder if extracting a subset of Spring MVC Test will necessarily help them? In other words are they manually setting up tests creating a Servlet and Filters, or are they using some test other test framework in which case it becomes more a question of how to make the Spring Security testing support usable outside of Spring MVC Test. In any case it's worth understanding better how this will help them.
Comment From: spring-projects-issues
Rob Winch commented
They are manually setting up the MockFilterChain and using MockHttpServletRequest/MockHttpServletResponse within the MockFilterChain. The assertions are asserting request attributes and properties on the MockHttpServletResponse.
Comment From: spring-projects-issues
Rossen Stoyanchev commented
Okay I see. Feel free to experiment with the contracts to see how easy or hard it might be. It shouldn't take very long to get a sense at least.
Comment From: spring-projects-issues
Andy Wilkinson commented
This could be of interest to Spring REST Docs too. I currently have an abstraction that's implemented for both MockMvc and REST Assured. See https://github.com/spring-projects/spring-restdocs/blob/master/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/Operation.java and its related types. Its design is almost certainly too REST Docs-specific, but perhaps it's a useful datapoint nonetheless. I'd gladly get rid of it in the REST Docs 2.0 / Spring Framework 5.0 timeframe.
Comment From: spring-projects-issues
Rob Winch commented
I've started the work on this in https://github.com/rwinch/spring-framework/tree/SPR-13818-mockhttp
NOTE: The branch is just a start (not nearly complete) and likely to be rebased changed etc.
Comment From: spring-projects-issues
Rob Winch commented
I've pushed some updates to this in the same branch https://github.com/rwinch/spring-framework/tree/SPR-13818-mockhttp I'd love some feedback on if you think this is headed in the right direction or not Rossen Stoyanchev
Comment From: spring-projects-issues
Rossen Stoyanchev commented
Andy Wilkinson from your perspective is it mainly about getting rid of Operation? Looking at that interface and related abstractions in the same package that goes a little deeper in representing the request and response in a framework independent way.
In this ticket there is no intent to abstract the use of the MockHttpServletRequest and Response. It's mainly about using any Servlet and also without dependency on spring-webmvc.
Comment From: spring-projects-issues
Andy Wilkinson commented
Yes, my interest was in possibly getting rid of Operation
. Your right that it does go deeper. I initially tried to use MockHttpServletRequest
and MockHttpServletResponse
but they didn't give me exactly what I needed. I was wondering if this was perhaps an opportunity to address that, but it sounds like the requirements don't quite line up.
Comment From: wagnerluis1982
What is the status for this issue?
Comment From: rstoyanchev
@wagnerluis1982 it's in the 5.x Backlog. Can you describe your use case?
Comment From: rstoyanchev
I'm closing this as we have no plans to work on it.