测试多部分文件上传时获取 400 响应代码而不是 200 代码

Getting 400 response code instead of 200 code when testing multipart files upload

我正在测试端点以上传一组多部分文件以及 String 参数。我收到 400 响应而不是 200 (OK)。关于为什么我得到 400 response 的任何想法,这表明我的请求对象有问题。但是当我检查请求时,内容类型是正确的。

uploadMyFiles.java 端点

@PostMapping(path = "/uploadMyFiles", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public Map<String, String> uploadMyFiles(MultipartFile[] multipartFiles, String userName) {
//..
return statusMap
}

我的测试用例

@Test
 public void testUploadMyFiles() throws Exception {
        byte[] byteContent = new byte[100];
        String userName ="testUser"
        
        MockMultipartFile filePart1 = new MockMultipartFile("files", "file1.pdf", "multipart/form-data", content);
        MultipartFile[] multipartFiles={filePart1}
        
        Object resultMap;
        when(myService.uploadMyFiles(multipartFiles,userName)).thenReturn(Map.of("file1.pdf", "Success"));

        MvcResult result = this.mockMvc.perform(MockMvcRequestBuilders.multipart("/uploadMyFiles")
                            .content(userName)
                            .content("{userName:testUser}") //tried with this too
                            .param("userName", "testUser")) //tried with this too 
                            .andExpect(status().isOk())
                            .andReturn();

        assertEquals(HttpStatus.OK, ((ResponseEntity)result.getAsyncResult()).getStatusCode());
    }

调试:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /uploadMyFiles
       Parameters = {userName=[testUser]}
          Headers = [Content-Type:"multipart/form-data", Content-Length:"23"]
             Body = <no character encoding set>
    Session Attrs = {}

回应

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

HTTP 400(在 spring-web 中)表示 RequestMapping 仅“部分映射”...

测试这个 Controller/RequestMapping:

@Controller
public class MyController {
    private static final Logger LOG = LoggerFactory.getLogger(MyController.class);

    @PostMapping(path = "/uploadMyFiles", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public @ResponseBody
    Map<String, String> uploadMyFiles(MultipartFile[] multipartFiles, String userName) {
        if (multipartFiles == null) {
            LOG.warn("multipartFiles is null!");
        } else {
            LOG.info("{} file{} uploaded.", multipartFiles.length, multipartFiles.length > 1 ? "s" : "");
            if (LOG.isDebugEnabled()) {
                for (MultipartFile mf : multipartFiles) {
                    LOG.debug("name: {}, size: {}, contentType: {}", mf.getOriginalFilename(), mf.getSize(), mf.getContentType());
                }
            }
        }
        // ...
        return Map.of("foo", "bar");
    }
}

这将是 MockMvc 测试的大纲(,它命中此控制器):

package com.example; // package of spring-boot-app

    
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;

import java.nio.charset.StandardCharsets;

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest
class Q66280300ApplicationTests {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testUploadMyFiles() throws Exception {
        byte[] byteContent1 = "text1".getBytes(StandardCharsets.US_ASCII);
        byte[] byteContent2 = "text2".getBytes(StandardCharsets.US_ASCII);
        String userName = "testUser";

        // IMPORTANT: name = "multipartFiles" (name of the request parameter)
        MockMultipartFile filePart1 = new MockMultipartFile("multipartFiles", "file1.txt", "text/plain", byteContent1);
        MockMultipartFile filePart2 = new MockMultipartFile("multipartFiles", "file2.txt", "text/plain", byteContent2);

        this.mockMvc.perform(
          multipart("/uploadMyFiles")
          .file(filePart1)
          .file(filePart2)
          .param("userName", userName)
        )
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(content().string(containsString("{\"foo\":\"bar\"}")));

    }
}

并且要找到您的文件(在控制器内、日志记录、null...)至关重要MockMultipartFile 的名称matches 请求参数的名称。 (在我们的例子中,方法参数的“默认”名称:"multipartFiles"

代码基于 Spring-boot-starter:2.4.3