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

