MockMvc GET请求返回200状态但无响应体问题排查
REST Controller测试响应体为空问题排查
问题现象
测试REST Controller时,接口返回200状态码但响应体为空;Postman调用同一接口可正常返回分页数据,怀疑Mockito的when()方法使用有误,但无法定位问题点。
测试代码
@WebMvcTest(PersonController.class) public class Testing { @MockBean PersonService personService; @MockBean JwtAuthenticationFilter jwtAuthenticationFilter; @Autowired ObjectMapper objectMapper; @Autowired MockMvc mockMvc; @Test @WithMockUser(username="tester") void test() throws Exception { PersonGetDTO person1 = new PersonGetDTO(1L, "FirstName1", "LastName1", "img1.png", LocalDateTime.of(LocalDate.of(2000, 01, 01), LocalTime.of(00, 00)) ); PersonGetDTO person2 = new PersonGetDTO(2L, "FirstName2", "LastName2", "img2.png", LocalDateTime.of(LocalDate.of(2000, 01, 01), LocalTime.of(00, 01)) ); List<PersonGetDTO> personList = new ArrayList<>(); personList.add(person1); personList.add(person2); Pageable pageable = Pageable.unpaged(); Page<PersonGetDTO> persons = new PageImpl<>(personList, pageable, personList.size()); when(personService.getPersons(Mockito.any(), Mockito.any())).thenReturn(ResponseEntity.ok(persons)); mockMvc.perform(get("/api/persons")) .andDo(print()); } }
测试响应结果
MockHttpServletResponse: Status = 200 Error message = null Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"] Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = []
Controller代码
@RestController @RequestMapping("/api/persons") public class PersonController { private final PersonService service; @Autowired public PersonController(PersonService service) { this.service = service; } @GetMapping @Operation( summary = "Returns a page of all persons " ) public ResponseEntity<Page<PersonGetDTO>> getPersons(@PageableDefault(page = 0, size = 5, sort = "dateTime", direction = Sort.Direction.DESC) Pageable pageable, @AuthenticationPrincipal User user) { return service.getPersons(pageable, user); } }
Service接口
public interface PersonService { ResponseEntity<Page<PersonGetDTO>> getPersons(Pageable pageable, User user); }
问题分析与解决方法
1. 请求未指定Accept头导致序列化未触发
测试中的mockMvc.perform未设置Accept请求头,Spring MVC无法确定响应格式,因此未对ResponseEntity的body进行序列化,导致响应体为空。
解决方法:在请求中添加Accept: application/json头:
mockMvc.perform(get("/api/persons") .accept(MediaType.APPLICATION_JSON)) .andDo(print());
2. Mockito参数匹配精度问题
原测试中使用Mockito.any()未指定具体类型,虽然理论上能匹配任意参数,但可能存在类型匹配的隐性问题。
解决方法:指定参数类型以确保匹配精确:
when(personService.getPersons(Mockito.any(Pageable.class), Mockito.any(User.class))) .thenReturn(ResponseEntity.ok(persons));
如果允许User参数为null,也可以用Mockito.isNull(User.class)替代第二个any()。
3. @AuthenticationPrincipal参数注入问题
使用@WithMockUser时,默认的principal是String类型的用户名,无法直接注入到User类型的参数中,导致user参数为null。虽然这不影响当前mock的匹配,但如果后续业务逻辑依赖User对象,会导致异常。
解决方法:自定义@WithMockUser的principal为User对象:
@Test @WithMockUser(username = "tester", principal = new User("tester", "password", Collections.emptyList())) void test() throws Exception { // 测试逻辑不变 }
或者配置AuthenticationPrincipalArgumentResolver来实现从Authentication到User的转换。
内容的提问来源于stack exchange,提问作者David Masson
相关产品推荐
相关产品推荐

