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

测试UserController时返回空而非预期对象问题排查

测试UserController创建/获取用户接口时断言失败的问题排查

问题描述

测试UserController的创建用户和获取用户方法时,出现断言失败错误,输出如下:

org.opentest4j.AssertionFailedError:
Expected :UserDTO(id=1, name=Steve, email=steve@mail.com, group=null)
Actual :

测试类代码如下:

@WebMvcTest(UserController.class)
class UserControllerTest {

  @MockBean private UserInterface userInterface;

  @Autowired private MockMvc mockMvc;

  @Test
  void create() throws Exception {
    UserCreationDTO user = new UserCreationDTO(1L, "Steve", "steve@mail.com", "password");

    Mockito.when(userInterface.create(user)).thenReturn(user);

    RequestBuilder request =
        MockMvcRequestBuilders.post("/api/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content(String.valueOf(user));

    MvcResult result = mockMvc.perform(request).andReturn();
    assertEquals(user, result.getResponse().getContentAsString());
  }

  @Test
  void getUser() throws Exception {
    UserDTO userDTO = new UserDTO(1L, "Steve", "steve@mail.com", null);

    Mockito.when(userInterface.getUser(1L)).thenReturn(userDTO);

    RequestBuilder request = MockMvcRequestBuilders.get("/api/users/1");

    MvcResult result = mockMvc.perform(request).andReturn();
    assertEquals(userDTO, result.getResponse().getContentAsString());
  }
}

错误原因及修复方案

1. 请求内容序列化错误

用String.valueOf(user)生成POST请求的JSON内容,本质是调用对象的toString()方法,生成的不是标准JSON格式,导致Controller无法解析请求,最终返回空内容。

修复:使用ObjectMapper将对象序列化为标准JSON字符串:

// 先注入ObjectMapper
@Autowired
private ObjectMapper objectMapper;

// 在create测试中替换content部分
.content(objectMapper.writeValueAsString(user))

2. Mockito参数匹配问题

Mockito.when(userInterface.create(user)).thenReturn(user)中直接传入user对象,Mockito会进行引用相等匹配。但Controller接收请求后会反序列化出一个新的UserCreationDTO对象,和测试里的user不是同一个引用,导致Mock逻辑不生效,返回null,接口最终返回空。

修复:使用参数匹配器any(UserCreationDTO.class)匹配任意该类型的对象:

Mockito.when(userInterface.create(Mockito.any(UserCreationDTO.class))).thenReturn(user);

3. 断言逻辑错误

直接把UserDTO/UserCreationDTO对象和result.getResponse().getContentAsString()(JSON字符串)做相等比较,对象和字符串永远不可能相等,必然断言失败。

修复:推荐使用MockMvc内置的JSON断言方法(更简洁):

mockMvc.perform(request)
       .andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(user)));

也可以将返回的JSON反序列化为对象后再比较:

String responseContent = result.getResponse().getContentAsString();
UserCreationDTO responseUser = objectMapper.readValue(responseContent, UserCreationDTO.class);
assertEquals(user, responseUser);

4. getUser测试的额外注意点

getUser测试中,除了上述断言问题,需添加accept(MediaType.APPLICATION_JSON)确保接口返回JSON格式,同时确认Controller的路径变量类型和测试中的1L一致,避免参数匹配失败。

修改后的完整测试类示例

@WebMvcTest(UserController.class)
class UserControllerTest {

  @MockBean private UserInterface userInterface;

  @Autowired private MockMvc mockMvc;
  @Autowired private ObjectMapper objectMapper;

  @Test
  void create() throws Exception {
    UserCreationDTO user = new UserCreationDTO(1L, "Steve", "steve@mail.com", "password");

    Mockito.when(userInterface.create(Mockito.any(UserCreationDTO.class))).thenReturn(user);

    RequestBuilder request =
        MockMvcRequestBuilders.post("/api/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(user));

    mockMvc.perform(request)
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(user)));
  }

  @Test
  void getUser() throws Exception {
    UserDTO userDTO = new UserDTO(1L, "Steve", "steve@mail.com", null);

    Mockito.when(userInterface.getUser(1L)).thenReturn(userDTO);

    RequestBuilder request = MockMvcRequestBuilders.get("/api/users/1")
            .accept(MediaType.APPLICATION_JSON);

    mockMvc.perform(request)
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andExpect(MockMvcResultMatchers.content().json(objectMapper.writeValueAsString(userDTO)));
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:31:17