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

Mockito单元测试问题:调用save()后Repository返回Null

解决Mockito中Repository.save()返回Null的问题

问题根源

核心问题是Mockito参数匹配不匹配:

  • 测试代码中你mock的是userDaoRepository.save(userToPassParam),指定返回预设的user对象
  • 但在Service的createUser方法中,会先修改传入的user对象的密码(user.setPassword(encodePassword)),再调用save(user)
  • 此时传入save的对象和mock时用的userToPassParam既不是同一个实例,字段值(密码)也不一致,Mockito找不到对应的mock规则,因此返回默认的null

修复方案

方案1:使用参数匹配器匹配任意User对象

最简单的方式是用any(User.class)作为参数匹配器,不管传入什么User实例,都返回预设的user:

// 替换原测试中save方法的mock代码
Mockito.when(userDaoRepository.save(Mockito.any(User.class))).thenReturn(user);

方案2:精准匹配实际传入的对象

提前模拟Service中对密码的修改逻辑,确保mock的参数和实际传入的对象一致:

@Test
void createUserNoExistValidConfirmation() throws Exception {
    User userToCallServiceImpl = new User();
    userToCallServiceImpl.setUserName("Username A");
    userToCallServiceImpl.setPassword("Pass A");
    userToCallServiceImpl.setConfirmPassword("Pass A");

    // 模拟密码加密结果
    String encodedPassword = "Pass A";
    Mockito.when(bCryptPasswordEncoder.encode(userToCallServiceImpl.getPassword())).thenReturn(encodedPassword);
    
    // 按业务逻辑mock用户名查询结果(若需验证用户名可用,应返回Optional.empty(),原测试逻辑可能需调整)
    Mockito.when(userDaoRepository.findByUserName(userToCallServiceImpl.getUserName())).thenReturn(Optional.ofNullable(user));

    // 创建与Service中save前完全一致的对象
    User modifiedUser = new User();
    modifiedUser.setUserName(userToCallServiceImpl.getUserName());
    modifiedUser.setPassword(encodedPassword);
    modifiedUser.setConfirmPassword(userToCallServiceImpl.getConfirmPassword());
    // 匹配该对象
    Mockito.when(userDaoRepository.save(Mockito.eq(modifiedUser))).thenReturn(user);

    User resultUser = userServiceImpl.createUser(userToCallServiceImpl);

    Assertions.assertEquals(user.getUserName(), resultUser.getUserName());
}

方案3:使用refEq忽略特定字段差异

如果User类的equals方法包含密码字段,可使用refEq匹配器忽略密码的变化:

// 替换原测试中save方法的mock代码,忽略password字段
Mockito.when(userDaoRepository.save(Mockito.refEq(userToCallServiceImpl, "password"))).thenReturn(user);

额外注意点

原测试中checkUserNameAvailable的mock逻辑可能存在业务矛盾:如果是验证用户名可注册,findByUserName应返回Optional.empty()(表示用户名未被占用),而非Optional.ofNullable(user)(表示用户名已存在)。若业务逻辑是“用户名不存在才允许创建”,此mock返回值会导致checkUserNameAvailable返回false,进而跳过save逻辑,最终也会返回null。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:51:53