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

单元测试中ResponseEntity返回fullname为null的异常问题排查

问题原因与解决方案:ResponseEntity中@JsonIgnore导致测试断言失败

问题现象

单元测试中,断言返回的EntityResponseDTO的fullname字段为"foobar"时失败,该字段返回null;但在控制器返回ResponseEntity之前,打印内存中的EntityResponseDTO对象,fullname的值却是正确的"foobar"。移除fullname字段上的@JsonIgnore注解后,测试通过。

测试代码

@Test
@DirtiesContext
public void createEntityTest() {
    EntityRequestDTO requestDTO = new EntityRequestDTO();
    dto.setTitle("foo");
    dto.setDescription("bar");
    ResponseEntity<EntityResponseDTO> postResponse = 
        testRestTemplate.postForEntity("/api/test", dto, EntityResponseDTO.class);
    EntityResponseDTO responseDTO = postResponse.getBody();
    
    assertThat(responseDTO.getTitle()).isEqualTo("foo");
    assertThat(responseDTO.getDescription()).isEqualTo("bar");
    assertThat(responseDTO.getFullname()).isEqualTo("foobar");
}

控制器代码

@PostMapping("/api/test")
public ResponseEntity<EntityResponseDTO> create(@RequestBody EntityRequestDTO requestDTO) {
    Entity saved = entityService.add(requestDTO);
    EntityResponseDTO savedDto = new EntityResponseDTO(saved);
    URI location = ServletUriComponentsBuilder
                .fromCurrentRequest()
                .path("/{id}")
                .buildAndExpand(saved.getId())
                .toUri();
    ResponseEntity<EntityResponseDTO> resEntity = ResponseEntity.created(location).body(savedDto);
    System.out.println("Before: ResponseEntity in controller.");
    System.out.println(resEntity.getBody().getFullname());
}

原因分析

  • @JsonIgnore注解的默认行为是同时控制序列化和反序列化:序列化Java对象为JSON时会忽略该字段,反序列化JSON为Java对象时也会跳过该字段的赋值。
  • 控制器中打印的是内存中的EntityResponseDTO实例,还未经过Jackson的序列化处理,所以fullname字段保留了服务层设置的值。
  • 当控制器返回ResponseEntity时,Spring会通过Jackson将EntityResponseDTO序列化为JSON响应体,此时@JsonIgnore生效,fullname字段不会被写入JSON。
  • TestRestTemplate接收到JSON响应后,会将其反序列化为EntityResponseDTO对象,由于响应体中没有fullname字段,该字段最终为null,导致断言失败。

解决方案

根据你的需求场景,可选择以下方案:

1. 保留字段但序列化时隐藏,反序列化时正常读取

将@JsonIgnore替换为@JsonProperty(access = JsonProperty.Access.WRITE_ONLY),该注解表示字段仅在**写入(序列化)**时被忽略,读取(反序列化)时仍会正常解析:

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String fullname;

2. 仅测试时验证该字段,生产环境保持隐藏

  • 编写测试专用的EntityResponseDTO类,去掉@JsonIgnore注解,测试时使用该类接收响应:
// 测试专用DTO
public class TestEntityResponseDTO extends EntityResponseDTO {
    @Override
    public String getFullname() {
        return super.getFullname();
    }
}
// 测试代码中替换为
ResponseEntity<TestEntityResponseDTO> postResponse = 
    testRestTemplate.postForEntity("/api/test", dto, TestEntityResponseDTO.class);
  • 或者直接测试服务层的entityService.add()方法,验证返回的Entity对象的fullname是否正确,跳过Controller层的HTTP序列化/反序列化环节。

3. 生产环境也需要返回该字段

直接移除fullname字段上的@JsonIgnore注解即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:44:55