You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用MockMvc测试带MultipartFile的POST API?400错误排查

问题排查与正确测试示例

我需要测试一个接收@Valid实体对象、BindingResult和MultipartFile参数的POST接口,根据Spring官方文档,测试时需使用MockMvc的multipart方法而非post,但实际测试时响应状态码为400,不符合预期的200。以下是我的测试代码、接口代码,请求排查问题并给出正确测试示例。

原测试类及方法

@Autowired
private MockMvc mockMvc;

@MockBean
private ProductService productService;

@Test
void newProduct() {
        // Given
        Product product = new Product("Test", "Diary", "Lorem 24", "fresh-pepper.jpg");
        product.setId(1L);
        product.setPath("dummy photo path");
        MockMultipartFile multipartFile = new MockMultipartFile("file",
                "fresh-pepper.jpg",
                "image/png, image/jpg, image/jpeg",
                "random image".getBytes());
        //When
        when(productService.saveProduct(product, multipartFile)).thenReturn(product);

        //Then
        try {
            this.mockMvc.perform(multipart("/dummy/api/v1/addNew")
                    .file(multipartFile))
                    .andDo(print())
                    .andExpect(status().isOk());

        } catch (Exception e) {
            e.printStackTrace();
        }

}

原Rest接口方法(类上标注@RequestMapping("/dummy/api/v1"))

@PostMapping(path = "/addNew", consumes = {MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<Product> newProduct(@Valid Product product,
                                          BindingResult bindingResult,
                                          @RequestParam("file") MultipartFile file) {
    if (bindingResult.hasFieldErrors()){
        bindingResult.getFieldErrors().forEach(fieldError -> LOGGER.error("Error " + fieldError.getField()));
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity<>(productService.saveProduct(product, file), HttpStatus.OK);
}

问题排查

  • 未传递Product实体参数:测试代码仅提交了MultipartFile,未传递Product的属性字段,导致@Valid校验失败,BindingResult检测到字段错误,接口返回400。
  • MockMultipartFile的ContentType格式错误:构造时传入多个用逗号分隔的MIME类型,不符合规范,应传入单个合法MIME类型(如image/jpeg)。
  • Mock参数匹配过严:when(productService.saveProduct(product, multipartFile))依赖对象实例匹配,但接口中接收的Product是从表单参数构建的新对象,与测试代码中的实例并非同一个,会导致Mock不生效。

正确测试示例

修改后的测试代码如下:

@Autowired
private MockMvc mockMvc;

@MockBean
private ProductService productService;

@Test
void newProduct() throws Exception {
    // Given
    String productName = "Test";
    String category = "Diary";
    String description = "Lorem 24";
    String imageName = "fresh-pepper.jpg";
    Long productId = 1L;
    String path = "dummy photo path";

    // 构造合法的MultipartFile
    MockMultipartFile multipartFile = new MockMultipartFile("file",
            imageName,
            "image/jpeg",
            "random image".getBytes());

    // 构造预期返回的Product对象
    Product expectedProduct = new Product(productName, category, description, imageName);
    expectedProduct.setId(productId);
    expectedProduct.setPath(path);

    // 使用参数匹配器避免实例严格匹配问题
    when(productService.saveProduct(any(Product.class), eq(multipartFile)))
            .thenReturn(expectedProduct);

    // 发起multipart请求,添加Product属性作为表单参数
    this.mockMvc.perform(multipart("/dummy/api/v1/addNew")
                    .file(multipartFile)
                    .param("name", productName)
                    .param("category", category)
                    .param("description", description)
                    .param("imageName", imageName)
                    .param("id", productId.toString())
                    .param("path", path))
            .andDo(print())
            .andExpect(status().isOk())
            // 校验返回的Product字段正确性
            .andExpect(jsonPath("$.id").value(productId))
            .andExpect(jsonPath("$.name").value(productName));
}

修改说明

  1. 添加Product表单参数:通过param()方法将Product的每个属性以表单字段形式传递,确保接口能正确实例化对象并通过@Valid校验。
  2. 修正MultipartFile的ContentType:改为单个合法的MIME类型,符合规范要求。
  3. 优化Mock参数匹配:使用any(Product.class)和eq(multipartFile)作为匹配器,避免实例不匹配导致的Mock失效。
  4. 移除冗余try-catch:直接抛出Exception,让JUnit自动处理,符合测试规范。
  5. 新增返回结果校验:通过jsonPath验证返回的Product字段,确保接口返回数据符合预期。

内容的提问来源于stack exchange,提问作者iTchTheRightSpot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:49:16