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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:53:13