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

JUnit Mockito测试报错:JSON路径$.title无值(状态码200正常)

Spring Boot Controller测试:updateProduct接口JSON断言失败问题

问题现象

测试updateProduct接口时,状态码返回200正常,但断言JSON路径$.title抛出错误:

java.lang.AssertionError: No value at JSON path "$.title"

查看响应详情,发现响应体为空,Content-Type为null。

初始化代码

@Autowired
private MockMvc mockMvc;

@MockBean
private ProductServiceImp productServiceImp;

@Autowired
private ObjectMapper objectMapper;

测试方法

@Test
@Order(3)
public void updateProductController_ShouldReturnOk() throws Exception {
    // Arrange
    when(productServiceImp.updateProduct(product, 1L)).thenReturn(product);

    // Act
    ResultActions response = mockMvc.perform(put("/api/products/{id}", 1L)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(product))
    );

    // Assert
    response.andExpectAll(
            status().isOk(),
            jsonPath("$.title", CoreMatchers.is(product.getTitle()))
    );
}

控制器代码

// 类上标注了@RequestMapping(value = "api/products")
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody Product product) {
    Product updatedProduct = productService.updateProduct(product, id);
    return ResponseEntity.ok(updatedProduct);
}

请求与响应详情

请求详情

MockHttpServletRequest:
      HTTP Method = PUT
      Request URI = /api/products/1
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"246"]
             Body = {"id":1,"title":"Fake Product","price":99999999,"rating":{"rate":5.0,"count":1},"category":"Fake Category","description":"Fake description","image":"FakeImage.jpg"}
    Session Attrs = {}

响应详情

MockHttpServletResponse:
           Status = 200
    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 = []

解决方案

1. 修正Mockito参数匹配逻辑

默认Mockito使用引用匹配,如果测试中传入的product对象和控制器接收的不是同一个实例,Mock的Service不会返回预设值,导致控制器返回空。改用参数匹配器:

// 替换原Arrange代码
when(productServiceImp.updateProduct(any(Product.class), eq(1L))).thenReturn(product);

需引入Mockito静态方法:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;

2. 检查Product类的序列化配置

确保Product类满足Jackson序列化要求:

  • 有无参构造器:
    public Product() {}
    
  • 所有需要序列化的属性都有对应的getter方法(比如getTitle())。

3. 修正Service注入匹配问题

控制器中注入的是productService(接口),但测试中Mock的是实现类ProductServiceImp,导致注入不匹配,控制器实际调用的不是Mock的Service。将测试中的MockBean改为接口类型:

@MockBean
private ProductService productService; // 替换原ProductServiceImp

同时调整Mockito语句:

when(productService.updateProduct(any(Product.class), eq(1L))).thenReturn(product);

4. 调试响应内容

在测试中添加响应打印,方便排查细节:

response.andDo(print()) // 在andExpectAll之前添加
        .andExpectAll(
                status().isOk(),
                jsonPath("$.title", CoreMatchers.is(product.getTitle()))
        );

内容的提问来源于stack exchange,提问作者モブ Mobu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 16:48:31