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

使用Mockito时变量值无法覆写的问题求助

问题:Mockito无法模拟save方法返回null属性的对象

我在测试followedByEntity为null的异常场景时,发现Mockito无法正确让userRepository.save()返回该属性为null的对象——即使尝试了when..Return()、doReturn()等方法,该属性始终不为null。只有把整个对象设为null,或者把逻辑抽成方法用Spy模拟才能生效,怀疑是对Mockito用法有误解。

业务代码

@Mock
UserRepository userRepository;

@Spy
@InjectMocks
UserServiceImpl userService;

@Override
public void followUser(UUID fromId, UUID toId) throws FollowerNotFoundException {

    Optional<UserEntity> userEntityOptionalFrom = userRepository.findById(fromId);
    Optional<UserEntity> userEntityOptionalTo = userRepository.findById(toId);

    if (userEntityOptionalFrom.isEmpty() || userEntityOptionalTo.isEmpty()) {
        throw new UserNotFoundException("No user found with this id");
    }

    UserEntity userEntityTo = userEntityOptionalTo.get();
    UserEntity userEntityFrom = userEntityOptionalFrom.get();

    Set<FollowingRequestEntity> followingRequestEntities = new HashSet<>();
    FollowingRequestEntity followingRequestEntity = FollowingRequestEntity.builder().userSenderEntity(userEntityFrom).userReceiverEntity(userEntityTo).build();
    followingRequestEntities.add(followingRequestEntity);

    userEntityTo.setFollowedByEntity(followingRequestEntities);

    userEntityTo = userRepository.save(userEntityTo);
    
    
    if (userEntityTo.getFollowedByEntity() == null || userEntityTo.getFollowedByEntity().isEmpty()) {
        throw new FollowerNotFoundException("Follower Not Found");
    }
}

public UserEntity setFollower(UserEntity userEntityTo, UserEntity userEntityFrom) { // 调用并Mock这个方法时测试能生效
    Set<FollowingRequestEntity> followingRequestEntities = new HashSet<>();
    FollowingRequestEntity followingRequestEntity = FollowingRequestEntity.builder().userSenderEntity(userEntityFrom).userReceiverEntity(userEntityTo).build();
    followingRequestEntities.add(followingRequestEntity);

    userEntityTo.setFollowedByEntity(followingRequestEntities);
    
    return userEntityTo;
}

测试代码(原代码)

@Test
void testFollowUser_ThrowsExceptionWhenFollowerIsFound() {

    UUID userFromId = randomUUID();
    UUID userToId = randomUUID();
    UserEntity userEntityFrom = getUserEntity();
    userEntityFrom.setId(userFromId);

    UserEntity userEntityTo = getUserEntity();
    userEntityTo.setId(userToId);
    userEntityTo.setName("new name");
   
  
when(userRepository.findById(userEntityFrom.getId())).thenReturn(Optional.of(userEntityFrom));
 when(userRepository.findById(userEntityTo.getId())).thenReturn(Optional.of(userEntityTo));


//        when(userRepository.save(userEntityTo)).thenReturn(userEntityTo);
    userEntityTo.setFollowerOfEntity(null);
    userEntityTo.setFollowedByEntity(null);
    doReturn(userEntityTo).when(userRepository).save(any());
//        when(userEntityTo.getFollowedByEntity()).thenReturn(null);
    
//        doReturn(userEntityTo).when(userService).setFollower(any(), any());
    
    FollowerNotFoundException exception =
            assertThrows(FollowerNotFoundException.class, () -> userService.followUser(userFromId, userToId));

    assertEquals("Follower Not Found", exception.getMessage());
}

问题原因

核心问题是对象引用复用:你在测试中修改的userEntityTo和业务方法中被操作的是同一个实例。业务方法里会先执行userEntityTo.setFollowedByEntity(followingRequestEntities)给这个对象的属性赋值,之后才调用save()。而你Mock的save()返回的就是这个已经被修改过的对象,所以followedByEntity自然不为null。

解决方案

创建一个独立的新UserEntity实例作为save()方法的返回值,将其followedByEntity设为null,其他属性和原对象保持一致即可。

修改后的测试代码

@Test
void testFollowUser_ThrowsExceptionWhenFollowerIsFound() {
    UUID userFromId = randomUUID();
    UUID userToId = randomUUID();
    
    // 准备findById返回的原对象
    UserEntity userEntityFrom = getUserEntity();
    userEntityFrom.setId(userFromId);

    UserEntity userEntityTo = getUserEntity();
    userEntityTo.setId(userToId);
    userEntityTo.setName("new name");

    // 准备save方法返回的对象:复制原对象属性,仅将followedByEntity设为null
    UserEntity savedUser = getUserEntity();
    savedUser.setId(userToId);
    savedUser.setName("new name");
    savedUser.setFollowerOfEntity(null);
    savedUser.setFollowedByEntity(null);

    // Mock findById方法
    when(userRepository.findById(userFromId)).thenReturn(Optional.of(userEntityFrom));
    when(userRepository.findById(userToId)).thenReturn(Optional.of(userEntityTo));
    
    // Mock save方法,返回我们预先准备好的、followedByEntity为null的对象
    doReturn(savedUser).when(userRepository).save(any(UserEntity.class));

    // 验证异常抛出
    FollowerNotFoundException exception = assertThrows(
        FollowerNotFoundException.class, 
        () -> userService.followUser(userFromId, userToId)
    );
    assertEquals("Follower Not Found", exception.getMessage());
}

说明

业务方法中userEntityTo = userRepository.save(userEntityTo)会把变量指向我们新创建的对象,此时该对象的followedByEntity为null,后续的判断逻辑就会触发FollowerNotFoundException,符合你的测试预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:50:23