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

Spring Boot Mockito测试中JPA Repository返回Null致空指针问题求助

问题分析与解决方案

核心原因

你遇到的问题本质是服务类中的Repository依赖未正确绑定到Mockito模拟对象,导致你配置的when(...).thenAnswer()逻辑未生效,Mock对象默认返回null,进而触发空指针异常。

分步解决方案

1. 为服务实例添加@InjectMocks注解

在测试类中,必须将你创建的所有@Mock依赖注入到目标服务实例中,否则服务会使用未初始化的真实依赖(或null),而非你配置的模拟对象。

修改后的完整测试类代码:

@ExtendWith(MockitoExtension.class) // 替代手动初始化,更简洁稳定
public class UserServiceImplTest {

    @Mock
    private UserRepository userRepository;

    @Mock
    private UserRoleRepository userRoleRepository;

    @Mock
    private CustomerRepository customerRepository;

    @Mock
    private PasswordEncoder passwordEncoder;

    // 关键:让Mockito自动将所有@Mock依赖注入到服务实例中
    @InjectMocks
    private UserServiceImpl userService;

    @Test
    public void testRegisterCustomerSuccess() {
        // Mock数据
        SignupRequest signupRequest = createSignupRequest();

        when(userRepository.findByUsernameOrEmail(signupRequest.getEmail())).thenReturn(Optional.empty());
        when(passwordEncoder.encode(signupRequest.getPassword())).thenReturn("encodedPassword");
        when(userRepository.save(any(User.class))).thenAnswer(invocation -> {
            User user = invocation.getArgument(0);
            user.setId(1L);
            return user;
        });
        when(userRoleRepository.save(any(UserRole.class))).thenAnswer(invocation -> {
            UserRole role = invocation.getArgument(0);
            role.setUserRoleId(1L);
            return role;
        });
        when(customerRepository.save(any(Customer.class))).thenAnswer(invocation -> {
            Customer customer = invocation.getArgument(0);
            customer.setId(1L);
            return customer;
        });

        // 调用服务方法
        assertDoesNotThrow(() -> userService.registerCustomer(signupRequest));

        // 验证交互
        verify(userRepository).findByUsernameOrEmail(signupRequest.getEmail());
        verify(passwordEncoder).encode(signupRequest.getPassword());
        verify(userRepository).save(any(User.class));
        verify(userRoleRepository).save(any(UserRole.class));
        verify(customerRepository).save(any(Customer.class));
    }

    // 实现测试数据构造方法
    private SignupRequest createSignupRequest() {
        SignupRequest request = new SignupRequest();
        request.setEmail("test@example.com");
        request.setPassword("123456");
        // 补充其他必要字段
        return request;
    }
}

2. 验证依赖注入有效性

调试时可添加以下代码,确认服务中的Repository是Mockito代理对象:

System.out.println(userRepository.getClass()); // 输出应为org.mockito...MockitoProxy相关类型

若输出为真实Repository实现类(如JpaRepository的代理类),说明注入失败,需检查:

  • 服务类的构造函数是否包含所有需要注入的Repository依赖(Mockito优先通过构造函数注入)
  • 服务类中的依赖字段是否为private且未被手动初始化

3. 兜底排查:确认Mock方法匹配逻辑

若注入正常但仍返回null,检查when()中的匹配器是否与服务调用的参数匹配:

  • 确认服务中调用save时的参数确实是User类型(避免子类/代理类导致any(User.class)不匹配)
  • 可临时替换为any()匹配器验证,再逐步缩小匹配范围

额外建议

  • 优先使用@ExtendWith(MockitoExtension.class)替代手动调用MockitoAnnotations.openMocks(this),减少初始化代码
  • 确保JPA Repository接口继承自Spring Data的Repository或其子接口,保证Mockito能正确生成代理对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:52:50