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

Spring Boot控制器MockMVC单元测试:JSON Path无法获取$.title字段

问题:单元测试中jsonPath无法获取Content实体的title字段

我在对控制器的GET请求方法做单元测试时,遇到jsonPath无法检索Content实体的"title"字段的问题。getContent()方法本身运行正常,但不清楚如何正确使用jsonPath获取所需信息。

待测试的控制器方法

@GetMapping("/{id}")
public ResponseEntity<ContentDTO> getContent(@PathVariable
                                             @Min(value = 1,
                                                  message = "{content.id.invalid}")
                                                  Integer id) throws ContentNotFoundException {
    Content content = contentService.getContent(id);
    return new ResponseEntity<ContentDTO>(contentMapper.entityToDTO(content), HttpStatus.OK);
}

控制器单元测试代码

@WebMvcTest
public class ContentControllerTest {

    @MockBean //if a testcase is dependent on Spring container Bean then use this method
    private ContentService contentService;

    @MockBean
    private ContentMapper contentMapper;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;


    private Content content;
    private Content content2;

    @BeforeEach
    void init(){
        content = new Content();
        content.setId(1);
        content.setTitle("test content title name");
        content.setDesc("test content description for a new content");
        content.setStatus(Status.PUBLISHED);
        content.setContentType(Type.ARTICLE);
        content.setDateCreated(LocalDateTime.now());
        content.setUrl("http://test.com");

        content2 = new Content();
        content2.setId(2);
        content2.setTitle("test content title name2");
        content2.setDesc("test content description for a new content2");
        content2.setStatus(Status.PUBLISHED);
        content2.setContentType(Type.ARTICLE);
        content2.setDateCreated(LocalDateTime.now());
        content2.setUrl("http://test2.com");
    }

    @Test
    void getContentValidTest() throws Exception { //TEST THAT IS FAILING
        //given

        //when
        Mockito.when(contentService.getContent(content.getId()))
                .thenReturn(content);

        ResultActions response = mockMvc
                .perform(get("/api/content/{id}", content.getId())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(content)));

        //then
        response.andExpect(status().isOk())
                .andExpect(jsonPath("$.title")
                        .value(content.getTitle()));

    }
}

错误信息

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

请求与响应详情

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /api/content/1
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"226"]
             Body = {"id":1,"title":"test content title name","desc":"test content description for a new content","status":"PUBLISHED","contentType":"ARTICLE","dateCreated":"2023-07-26T17:14:50.8809845","dateUpdated":null,"url":"http://test.com"}
    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 = []

Postman成功响应示例

{
    "title": "My Spring Data Blog Post",
    "desc": "A post about spring data",
    "status": "IDEA",
    "contentType": "ARTICLE",
    "dateCreated": "2023-06-17T22:39:52",
    "dateUpdated": null,
    "url": null
}

解决方案

问题根源

  1. ContentMapper未mock转换逻辑:用@MockBean标注了ContentMapper,但未定义entityToDTO方法的返回值,默认返回null。控制器调用该方法得到null,最终响应体为空,导致jsonPath找不到$.title。
  2. GET请求冗余传递请求体:GET请求规范上不需要携带请求体,测试代码里的.content(objectMapper.writeValueAsString(content))属于冗余操作,可移除。

修改后的测试代码

@Test
void getContentValidTest() throws Exception {
    // 1. 创建对应的ContentDTO实例(根据实际DTO构造器调整字段赋值)
    ContentDTO contentDTO = new ContentDTO();
    contentDTO.setTitle(content.getTitle());
    contentDTO.setDesc(content.getDesc());
    contentDTO.setStatus(content.getStatus());
    contentDTO.setContentType(content.getContentType());
    contentDTO.setDateCreated(content.getDateCreated());
    contentDTO.setUrl(content.getUrl());

    // 2. mock mapper的转换方法,指定返回目标DTO
    Mockito.when(contentMapper.entityToDTO(content))
            .thenReturn(contentDTO);
    // mock service的返回结果
    Mockito.when(contentService.getContent(content.getId()))
            .thenReturn(content);

    // 3. 执行GET请求,移除冗余的请求体参数
    ResultActions response = mockMvc
            .perform(get("/api/content/{id}", content.getId())
                    .contentType(MediaType.APPLICATION_JSON));

    // 4. 断言响应内容
    response.andExpect(status().isOk())
            .andExpect(jsonPath("$.title").value(content.getTitle()));
}

关键说明

  • 必须为ContentMapper的entityToDTO方法mock返回值,确保控制器能拿到有效的ContentDTO并序列化到响应体中。
  • 移除GET请求的冗余请求体,让测试逻辑更贴合实际接口行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:15:59