Spring Boot单元测试报错:EmpresaRepository为Null致测试失败
测试方法执行失败:NullPointerException问题排查与解决
报错信息
java.lang.NullPointerException: Cannot invoke "com.priserp.springapipeta.repository.EmpresaRepository.findAll()" because "this.empresaRepository" is null
报错堆栈:
at com.priserp.springapipeta.service.EmpresaService.getAllEmpresas(EmpresaService.java:53) at com.priserp.springapipeta.unit.service.EmpresaServiceTest.should_Return_All_Empresas(EmpresaServiceTest.java:66) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
服务类代码
@Service public class EmpresaService { private final EmpresaRepository empresaRepository; public List<Empresa> getAllEmpresas() { return empresaRepository.findAll(); } } @Repository public interface EmpresaRepository extends JpaRepository<Empresa, Long> { Optional<Empresa> findByRazaoSocial(String name); Optional<Empresa> findByCnpj(String cnpj); }
测试类代码
@RunWith(MockitoJUnitRunner.class) @SpringBootTest(classes = PetaApiApplication.class) class EmpresaServiceTest { @Mock EmpresaRepository empresaRepository; @InjectMocks EmpresaService empresaService = new EmpresaService(empresaRepository); private final List<Empresa> empresas = new ArrayList<>(); @Test public void should_Return_All_Empresas() { Empresa empresa1 = new Empresa(1L, "EMPRESA 1", "12345678"); Empresa empresa2 = new Empresa(2L, "EMPRESA 2", "456"); empresas.add(empresa1); empresas.add(empresa2); when(empresaRepository.findAll()).thenReturn(empresas); List<Empresa> foundEmpresas = this.empresaService.getAllEmpresas(); assertNotEquals(null, foundEmpresas); assertEquals("EMPRESA 1", foundEmpresas.get(0).getRazaoSocial()); System.out.println(foundEmpresas.size()); System.out.println(empresas.size()); } }
问题原因与修复方案
核心问题
- 服务类缺少构造函数:
EmpresaService中声明了final修饰的empresaRepository,但没有提供构造函数,Spring无法通过构造注入的方式为其赋值,导致运行时repository为null。 - 测试类注解冲突:同时使用
@RunWith(MockitoJUnitRunner.class)和@SpringBootTest会导致上下文混乱——前者用于纯Mockito单元测试(无需启动Spring上下文),后者会启动完整的Spring应用上下文,两者混用会破坏依赖注入逻辑。 - 手动实例化与注解冲突:同时使用
@InjectMocks和手动new EmpresaService(empresaRepository),会导致Mockito的注入逻辑失效。
修复步骤
1. 修复服务类,添加构造函数
为EmpresaService添加构造函数,让Spring能够完成依赖注入:
@Service public class EmpresaService { private final EmpresaRepository empresaRepository; // 添加构造函数用于依赖注入 public EmpresaService(EmpresaRepository empresaRepository) { this.empresaRepository = empresaRepository; } public List<Empresa> getAllEmpresas() { return empresaRepository.findAll(); } }
2. 调整测试类(二选一)
方案一:纯Mockito单元测试(推荐)
去掉@SpringBootTest,用纯Mockito进行单元测试,无需启动Spring上下文:
@RunWith(MockitoJUnitRunner.class) class EmpresaServiceTest { @Mock EmpresaRepository empresaRepository; @InjectMocks EmpresaService empresaService; // 无需手动new,@InjectMocks会自动创建实例并注入Mock @Test public void should_Return_All_Empresas() { // 准备测试数据 List<Empresa> empresas = new ArrayList<>(); Empresa empresa1 = new Empresa(1L, "EMPRESA 1", "12345678"); Empresa empresa2 = new Empresa(2L, "EMPRESA 2", "456"); empresas.add(empresa1); empresas.add(empresa2); // Mock Repository行为 when(empresaRepository.findAll()).thenReturn(empresas); // 调用服务方法 List<Empresa> foundEmpresas = empresaService.getAllEmpresas(); // 断言验证 assertNotNull(foundEmpresas); assertEquals(2, foundEmpresas.size()); assertEquals("EMPRESA 1", foundEmpresas.get(0).getRazaoSocial()); } }
方案二:Spring Boot集成测试
如果需要启动Spring上下文进行集成测试,使用@MockBean替换@Mock和@InjectMocks:
@SpringBootTest class EmpresaServiceTest { @MockBean EmpresaRepository empresaRepository; @Autowired EmpresaService empresaService; @Test public void should_Return_All_Empresas() { List<Empresa> empresas = new ArrayList<>(); Empresa empresa1 = new Empresa(1L, "EMPRESA 1", "12345678"); Empresa empresa2 = new Empresa(2L, "EMPRESA 2", "456"); empresas.add(empresa1); empresas.add(empresa2); when(empresaRepository.findAll()).thenReturn(empresas); List<Empresa> foundEmpresas = empresaService.getAllEmpresas(); assertNotNull(foundEmpresas); assertEquals(2, foundEmpresas.size()); assertEquals("EMPRESA 1", foundEmpresas.get(0).getRazaoSocial()); } }
内容的提问来源于stack exchange,提问作者Gilmar
相关产品推荐
相关产品推荐

