SpringBoot API测试返回空JSON,Postman请求正常问题求助
SpringBoot API测试问题:MockMvc请求返回空JSON,Postman正常
问题现象
测试类中执行GET请求/employee/1时,MockHttpServletResponse的Body为空,抛出断言错误java.lang.AssertionError: No value at JSON path "$.firstName";但用Postman执行相同请求能正常获取正确结果。
相关日志
MockHttpServletRequest: HTTP Method = GET Request URI = /employee/1 Parameters = {} Headers = [] Body = null Session Attrs = {} Handler: Type = com.openclassrooms.api.controller.EmployeeController Method = com.openclassrooms.api.controller.EmployeeController#getEmployee(Long) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = [] Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = []
问题原因
测试类中使用@MockBean注解创建了EmployeeService的Mock实例,但没有为该Mock对象的getEmployee方法设置模拟返回值。当Controller调用employeeService.getEmployee(1L)时,Mock对象默认返回Optional.empty(),导致Controller返回的响应Body为空,最终断言失败。而Postman运行时使用的是真实的EmployeeService实例,会连接数据库查询真实数据,所以能正常返回结果。
解决方案
使用Mockito为Mock的EmployeeService设置方法调用的返回值,模拟存在目标Employee的场景。
修改后的测试类代码
package com.openclassrooms.api; import static org.hamcrest.CoreMatchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.Optional; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import com.openclassrooms.api.controller.EmployeeController; import com.openclassrooms.api.models.Employee; import com.openclassrooms.api.service.EmployeeService; @WebMvcTest(controllers = EmployeeController.class) public class EmployeeControllerTest { @Autowired private MockMvc mockMvc; @MockBean private EmployeeService employeeService; @Test public void testGetEmployeeById() throws Exception { // 模拟测试数据 Employee mockEmployee = new Employee(); mockEmployee.setId(1L); mockEmployee.setFirstName("Laurent"); mockEmployee.setLastName("Dupont"); mockEmployee.setMail("laurent.dupont@mail.com"); mockEmployee.setPassword("password123"); // 为Mock的Service设置返回值 when(employeeService.getEmployee(1L)).thenReturn(Optional.of(mockEmployee)); mockMvc.perform(get("/employee/1") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(print()) .andExpect(jsonPath("$.firstName", is("Laurent"))); } }
额外优化建议
- 规范测试方法命名:原测试方法名
testGetEmployees与测试单个员工的逻辑不符,改为testGetEmployeeById更清晰。 - 指定请求MediaType:在
perform中添加.contentType(MediaType.APPLICATION_JSON),让请求更符合REST API规范。 - 避免返回null:Controller中的
getEmployee(Long id)方法,当emp为空时不要返回null,直接返回emp(即Optional.empty()),避免返回null引发的序列化问题或空指针风险:
@GetMapping("/employee/{id}") public Optional<Employee> getEmployee(@PathVariable("id") final Long id) { Optional<Employee> emp = employeeService.getEmployee(id); if (emp.isPresent()) { System.out.println(emp.get().getFirstName()); } else { System.out.println("ABSENT"); } return emp; }
内容的提问来源于stack exchange,提问作者Bhorah
相关产品推荐
相关产品推荐

