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

如何在MockMvc POST请求测试中获取响应体?

MockMvc POST测试无响应体问题排查与解决

问题场景

在Spring Boot的Controller集成测试中,发送POST请求后无法获取响应体,报错com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input,响应体为空。

相关代码

StudentController

@RestController
public class StudentController {

    @Autowired
    StudentService studentService;

    @PostMapping("/add-student")
    public ResponseEntity<Student> addStudent(@RequestBody Student student) {
        return new ResponseEntity<>(studentService.addStudent(student), HttpStatus.CREATED);
    }
}

StudentService

@Service
public class StudentService {
    public Student addStudent(Student student) {
        return student;
    }
}

Student实体类

public class Student {
    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

原测试类

@WebMvcTest
class StudentControllerTest {

    @Autowired
    MockMvc mockMvc;

    @InjectMocks
    StudentController studentController;

    @Autowired
    ObjectMapper objectMapper;

    @MockBean
    private StudentService studentService;

    @Test
    void addStudent() throws Exception {

        Student student = new Student();
        student.setName("pushpak");

        Mockito.when(studentService.addStudent(student)).thenReturn(student);

        MockHttpServletResponse response = mockMvc
                .perform(post("/add-student")
                        .content(objectMapper.writeValueAsString(student))
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON)
                ).andReturn().getResponse();
        Assertions.assertEquals(student.getName(), objectMapper.readValue(response.getContentAsString(), Student.class).getName());
    }
}

报错信息

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /add-student
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"18"]
             Body = {"name":"pushpak"}
    Session Attrs = {}

Handler:
             Type = com.myapp.spring_boot_test.controller.StudentController
           Method = com.myapp.spring_boot_test.controller.StudentController#addStudent(Student)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 201
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
...(省略栈跟踪)

问题原因

  1. Mockito匹配逻辑错误:测试中用Mockito.when(studentService.addStudent(student)).thenReturn(student)进行实例精确匹配,但Spring MVC接收到JSON后会反序列化为全新的Student对象,和测试代码里的实例不是同一个,导致Mock方法未触发,Service返回null,响应体为空。
  2. 冗余注解冲突:@WebMvcTest已经会自动配置Controller,手动加@InjectMocks会干扰Spring的自动注入逻辑,可能引发依赖注入异常。

解决方案

1. 修改Mockito匹配方式

使用any(Student.class)参数匹配器,匹配任意Student类型的参数:

Mockito.when(studentService.addStudent(Mockito.any(Student.class))).thenReturn(student);

2. 移除冗余注解

删除测试类中的@InjectMocks StudentController studentController;,让@WebMvcTest自动管理Controller实例。

3. 优化断言方式(可选)

用MockMvc的andExpect直接验证响应,代码更简洁:

mockMvc.perform(post("/add-student")
                .content(objectMapper.writeValueAsString(student))
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isCreated())
        .andExpect(jsonPath("$.name").value(student.getName()));

修改后的完整测试类

@WebMvcTest
class StudentControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @MockBean
    private StudentService studentService;

    @Test
    void addStudent() throws Exception {

        Student student = new Student();
        student.setName("pushpak");

        // 使用参数匹配器
        Mockito.when(studentService.addStudent(Mockito.any(Student.class))).thenReturn(student);

        // 方式一:直接用andExpect验证
        mockMvc.perform(post("/add-student")
                        .content(objectMapper.writeValueAsString(student))
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isCreated())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$.name").value(student.getName()));

        // 方式二:获取响应体后验证(按需使用)
        /*MockHttpServletResponse response = mockMvc.perform(post("/add-student")
                        .content(objectMapper.writeValueAsString(student))
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                .andReturn().getResponse();
        Assertions.assertEquals(student.getName(), objectMapper.readValue(response.getContentAsString(), Student.class).getName());*/
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:08:10