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

测试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:50:37