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 }
解决方案
问题根源
- ContentMapper未mock转换逻辑:用
@MockBean标注了ContentMapper,但未定义entityToDTO方法的返回值,默认返回null。控制器调用该方法得到null,最终响应体为空,导致jsonPath找不到$.title。 - 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
相关产品推荐
相关产品推荐

