测试UserService的updateUser方法时出现Wanted but not invoked错误排查
问题分析与解决方案
错误原因拆解
首先要明确:根本不是save()被调用了两次。错误信息里显示的"2 interactions"是指总共有2次和mock对象的交互:1次findById(),1次save(),并非save()执行了两次。
真正的问题出在参数匹配失败:
- 你在测试中验证
save(userUpdate),但userUpdate的name字段是"user" - 而业务代码里实际调用
save()时传入的User对象,是由userDto转换而来,name字段是"user user" - 加上
User类没有正确重写equals()和hashCode()方法,Mockito无法识别这两个对象为"匹配",因此报错说"期望的调用未发生"。
修复步骤
1. 修正测试中的对象匹配逻辑
有两种可选方案:
- 方案一:让测试中的
userUpdate对象字段和userDto完全一致 - 方案二:使用参数匹配器替代具体对象验证,比如:
// 验证save被调用1次,不限制具体参数 verify(userRepository, times(1)).save(any(User.class)); // 或者自定义匹配规则,验证关键字段 verify(userRepository, times(1)).save(argThat(user -> user.getUserId().equals(userId) && user.getName().equals(userDto.getName()) && user.getEmail().equals(userDto.getEmail()) ));
2. 给User类重写equals()和hashCode()
这是Mockito参数匹配的基础,确保内容相同的对象能被识别为相等。可以用Lombok的@EqualsAndHashCode注解快速实现,或者手动重写方法。
3. 优化业务代码(可选)
业务代码中的map(Function.identity())是冗余操作,不会改变流中的元素,可以直接删除:
@Override public Mono<User> updateUser(Long userId, UserDto userDto) { return userRepository.findById(userId) .flatMap(user -> { User updateUser = UserMapper.USER_MAPPER_INSTANCE.toUser(userDto); updateUser.setUserId(userId); return userRepository.save(updateUser); }) .switchIfEmpty(Mono.error(new Exception("User not found!"))); }
修正后的测试代码示例
@Test void updateUser() { // given Long userId = 1L; String username = "user123"; String userName = "user user"; // 与userDto的name保持一致 UserDto userDto = new UserDto( username, userName, "user123@gmail.com", LocalDate.now().toString(), 9843807187L, "password", Role.ADMIN ); User user1 = new User( 1L, username, "password", userName, "user123@gmail.com", 9843807187L, LocalDate.now(), Role.ADMIN ); User userUpdate = new User( 1L, username, "password", userName, // 修正为与userDto一致的name "user123@gmail.com", 9843807187L, LocalDate.now(), Role.ADMIN ); //when when(userRepository.findById(userId)).thenReturn(Mono.just(user1)); when(userRepository.save(any(User.class))) .thenReturn(Mono.just(userUpdate)); // Then Mono<User> updatedUser = serviceUnderTest.updateUser(userId, userDto); StepVerifier.create(updatedUser) .expectNext(userUpdate) .verifyComplete(); verify(userRepository, times(1)).findById(userId); verify(userRepository, times(1)).save(userUpdate); }
内容的提问来源于stack exchange,提问作者AM0007
相关产品推荐
相关产品推荐

