Inconsistencies in MockMvc
's file()
and part()
handling and their impact on functional endpoints
#34197
Labels
in: test
Issues in the test module
status: waiting-for-triage
An issue we've not yet triaged or decided on
Spring REST Docs was the first to identify this issue: spring-projects/spring-restdocs#953
Current Situation
As evident in this issue, using the
part()
method instead offile()
for multipart uploads in Spring REST Docs results in duplicate file entries within the generated documentation.While I've submitted an issue and a proposed ad-hoc solution to Spring REST Docs, I believe the root cause lies in the somewhat ambiguous behavior of
MockHttpServletRequest
orMockMultipartHttpServletRequestBuilder
.Here's a breakdown of the sequence of events when uploading multipart data using
MockMvc
:MockMultipartHttpServletRequest
internally managesmultipartFiles
as separate file types. When usingMockMultipartHttpServletRequestBuilder
to create a mock multipart request, files can be added using either thepart
method to add aMockPart
or thefile
method to add aMockMultipartFile
.The actual servlet creation process is implemented as follows:
As shown in the code, files added using the
file
method are only processed usingaddFile
. However, files added using thepart
method are processed using bothaddPart
andaddFile
, resulting in duplicate data being included in the servlet creation.Multipart in Spring
I believe there are primarily two ways to handle multipart data on Spring servers:
@RequestParam("file") MultipartFile file
: This is the more traditional approach, commonly used in standard controller methods.request.multipartData().getFirst("file")
: This method is primarily used in functional endpoints, providing a more flexible but manual way to handle multipart data. (As far as I know, traditional controllers also use this manual approach to handle file uploads.)An example using functional endpoints is shown below:
Problems
When using
MockMvc
to simulate these requests, a couple of issues arise:Missing Part Data for
.file()
: When creating mock multipart data using thefile()
method, the corresponding part data is not populated. This means that methods likerequest.multipartData().getFirst("file")
cannot retrieve the file using the part mechanism. This is a limitation inherent toMockMvc
.Duplicate Entries in REST Docs: RestDocs, when generating documentation, attempts to handle this discrepancy by checking if the request is of type
MockMultipartHttpServletRequest
. If it is, REST Docs extracts file information from the files collection.This appears to be an ad-hoc workaround implemented in rest-docs to handle the scenario where no file info in parts collection.
However, when using the
part()
method to create aMockMultipartHttpServletRequest
, the same file is extracted twice, once from the parts collection and once from the files collection. This results in duplicate entries in the generated documentation.Currently, the clearest solution I see is:
1.2. To achieve consistency in the operation pipeline between
@RequestParam("file") MultipartFile file
andrequest.multipartData().getFirst("file")
, we might need to modify not only the Mock but also the servlet structure.1
, remove the dependency onMockMultipartHttpServletRequest
in rest-docs.However, I don't have a clear solution to address this situation comprehensively, as I'm not familiar with all the dependencies within the Spring Framework.
Therefore, I've created this issue to discuss it further before making any modifications.
The text was updated successfully, but these errors were encountered: