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

Service层update方法单元测试抛出UserNotFoundException及Mock测试卡在isEmpty检查异常问题求助

问题排查与修复方案

嘿,我帮你揪出了几个关键问题,先从最核心的代码错误说起:

首先是Service层updateUser的致命逻辑错误

你看这段代码:

Optional<UserEntity> databaseUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));

你居然用updatedUser.getUserName()转成Integer去查询用户?这完全不符合逻辑啊!update方法的第一个参数id才是用来查询用户的标识,正确的写法应该是:

Optional<UserEntity> databaseUser = userRepository.findById(Integer.valueOf(id));

这就是测试一直抛出UserNotFoundException的根本原因——你查的是userName对应的"id",而不是传入的真实用户id,自然查不到数据。

接下来是测试代码里的几个坑

1. 没Mock用户查询的返回值

你的测试只Mock了roleRepository.findById和userRepository.save,但完全没处理userRepository.findById的调用!Mock的Repository默认会返回Optional.empty(),所以一执行到判断isEmpty()就直接抛异常了。

你需要在测试里加上:

// 模拟根据传入的id能查到用户
when(userRepository.findById(id)).thenReturn(Optional.of(new UserEntity()));

2. userRepository.save的Mock写法错误

userEntity.setId(id)是void方法,不能直接放在thenReturn()里,得先创建好实体并设置id,再返回:

UserEntity userEntity = userService.mapToUserEntity(userDto);
userEntity.setId(id); // 先设置id
when(userRepository.save(any(UserEntity.class))).thenReturn(userEntity);

3. 重复调用了update方法

你的测试里连续调用了两次userService.updateUser,这不仅多此一举,还可能导致状态混乱,删掉第一次调用就行:

// 删掉这行重复的调用
// userService.updateUser(String.valueOf(id), userDto);
var actualUser = userService.updateUser(String.valueOf(id), userDto);

4. 预期DTO的属性设置时机不对

你是在调用update之后才给userDto.setUserName(String.valueOf(id)),这时候断言肯定不相等啊!要在调用update之前就把DTO的属性调整好,保证和实际返回的DTO属性一致。

修复后的完整测试代码

@Test
void updateUserTest(){
    final int id = 1;
    final long roleId = 2L;
    UserDTO userDto = new UserDTO();
    // 提前设置正确的userName(或者根据你的业务逻辑调整)
    userDto.setUserName(String.valueOf(id));
    userDto.setId(String.valueOf(id));
    userDto.setName(new UserDTO.Name("surname", "firstname", "patronymic"));
    userDto.setActive(true);
    userDto.setEmails(List.of(new UserDTO.Email("email", "external")));
    userDto.setRoles(List.of("2"));
    userDto.setLastAccessDate(LocalDateTime.of(2022, 10, 25, 4, 20));
    userDto.setUnit(null);

    // 模拟角色查询
    when(roleRepository.findById(anyLong())).thenReturn(Optional.of(new UserEntity.Role(roleId)));
    // 模拟用户存在
    when(userRepository.findById(id)).thenReturn(Optional.of(new UserEntity()));
    // 构造保存的实体并Mock save方法
    UserEntity userEntity = userService.mapToUserEntity(userDto);
    userEntity.setId(id);
    when(userRepository.save(any(UserEntity.class))).thenReturn(userEntity);

    // 执行测试
    var actualUser = userService.updateUser(String.valueOf(id), userDto);

    // 断言
    assertEquals(userDto, actualUser);
}

额外提醒

别忘了检查mapToUserEntity和map(把实体转DTO)的转换方法,确保属性映射完全正确——很多时候断言失败都是因为转换时漏了属性或者映射错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:14:07