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

SpringBootTest空指针异常:UserRepository为null导致方法调用失败

解决UserService测试中的NullPointerException问题

问题原因

你的测试类同时混用了Mockito单元测试注解和SpringBoot集成测试注解,导致依赖注入异常:

  1. @SpringBootTest会启动完整的Spring上下文,但你又用了@ExtendWith(MockitoExtension.class)做Mock测试,两者冲突。
  2. 用@Autowired注入UserRepository和UserConverter在Mockito单元测试环境下不会生效,这些依赖实际是null,进而导致Service里的userRepository为null。
  3. MockitoAnnotations.openMocks(this)在使用@ExtendWith(MockitoExtension.class)时属于冗余代码,该扩展会自动初始化Mock实例。

修正方案

1. 调整测试类注解与依赖注入方式

移除@SpringBootTest,改用@Mock模拟Service依赖,@InjectMocks自动将Mock注入到Service中:

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    // 用@Mock模拟依赖
    @Mock
    private UserRepository userRepository;
    @Mock
    private UserConverter userConverter;

    // @InjectMocks自动将上面的Mock注入到userService中
    @InjectMocks
    private UserService userService;

    @Test
    public void findByUsername200() throws Exception {
        String name = "luxubu@gmail.com";

        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(name);

        // 模拟Repository的返回值
        when(userRepository.findByUsername(name)).thenReturn(userEntity);

        UserDTO mockUserDTO = new UserDTO();
        mockUserDTO.setUsername(name);
        // 模拟Converter的转换结果
        when(userConverter.UserToUserDTO(userEntity)).thenReturn(mockUserDTO);

        UserDTO actualResult = userService.findByUsername(name);

        assertEquals(mockUserDTO.getUsername(), actualResult.getUsername());
        // 验证Repository的方法是否被调用
        verify(userRepository, times(1)).findByUsername(name);
    }
}

2. 优化UserService的依赖注入方式(可选但推荐)

为了让Mockito的@InjectMocks更可靠,建议Service类使用构造函数注入替代字段注入:

@Service
public class UserService {
    private final UserRepository userRepository;
    private final UserConverter userConverter;

    // 构造函数注入,Spring会自动装配依赖
    public UserService(UserRepository userRepository, UserConverter userConverter) {
        this.userRepository = userRepository;
        this.userConverter = userConverter;
    }

    @Override
    public UserDTO findByUsername(String username) {
        UserEntity user = userRepository.findByUsername(username);
        if (user == null) throw new CustomException.NotFoundException("Không tìm thấy người dùng " + username);
        return userConverter.UserToUserDTO(user);
    }
}

额外说明

  • 如果确实需要做集成测试(比如要测试真实的数据库交互),则保留@SpringBootTest,移除@ExtendWith(MockitoExtension.class)和@Mock、@InjectMocks,直接用@Autowired注入所有Bean,但这种场景下你需要准备测试数据或者用测试容器。
  • 单元测试的核心是隔离依赖,所以用Mock模拟Repository和Converter是正确的做法,不需要启动真实的Spring上下文。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:27:18