Spring Boot JUnit测试中Repository空指针异常求助
解决Spring Boot JUnit测试中Repository返回空值触发NPE的问题
问题分析
你的测试代码存在几个关键问题:
- 手动设置自增ID:
Employee主键使用GenerationType.IDENTITY自增策略,但测试中手动指定id=1L,干扰了数据库自增逻辑,save操作后原对象ID不会被数据库更新,直接断言原对象ID会不符合预期。 - 测试分层混淆:类名是
EmployeeControllerTest,但你用了@DataJpaTest(用于测试Repository层),未测试Controller接口逻辑,反而直接操作Repository。 - 数据库配置问题:
@DataJpaTest默认使用嵌入式内存数据库(如H2),不会连接你配置的PostgreSQL,若期望用真实库测试需额外配置。 - Mockito未正确使用:你提到用Mockito,但当前测试完全依赖真实Repository,未用到Mock逻辑。
解决方案
方案1:修正Repository层测试(用@DataJpaTest)
如果目标是测试Repository的save方法,修改测试代码如下:
@DataJpaTest // 若要连接真实PostgreSQL,添加以下注解,否则默认用H2内存库 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class EmployeeRepositoryTest { // 类名改为对应Repository测试更清晰 @Autowired private EmployeeRepository employeeRepository; @Test public void addEmployeeTest() { // 不要手动设置id,交给数据库自增生成 Employee employee = Employee.builder() .firstName("abc") .lastName("def") .email("abc@xyz.com") .build(); // 接收save方法返回的实体,该实体包含数据库生成的ID Employee savedEmployee = employeeRepository.save(employee); assertThat(savedEmployee.getId()).isGreaterThan(0L); } }
方案2:正确测试Controller层(用Mockito+@WebMvcTest)
如果目标是测试Controller的createEmployee接口,这才是Mockito的典型使用场景,代码如下:
@WebMvcTest(EmployeeController.class) public class EmployeeControllerTest { @Autowired private MockMvc mockMvc; // Mock依赖的EmployeeRepository,避免依赖真实数据库 @MockBean private EmployeeRepository employeeRepository; @Test public void createEmployeeTest() throws Exception { // 构造请求参数 Employee requestEmployee = Employee.builder() .firstName("abc") .lastName("def") .email("abc@xyz.com") .build(); // 构造模拟的返回结果 Employee mockSavedEmployee = Employee.builder() .id(1L) .firstName("abc") .lastName("def") .email("abc@xyz.com") .build(); // 指定当调用Repository的save方法时,返回模拟的实体 when(employeeRepository.save(any(Employee.class))).thenReturn(mockSavedEmployee); // 发送POST请求测试接口 mockMvc.perform(post("/api/v1/employees") .contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString(requestEmployee))) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)) .andExpect(jsonPath("$.firstName").value("abc")) .andExpect(jsonPath("$.lastName").value("def")) .andExpect(jsonPath("$.email").value("abc@xyz.com")); } }
关键说明
- 自增ID处理:
IDENTITY策略下,数据库会自动生成ID,save方法返回的实体才包含最新的ID,原对象的ID不会被自动更新。 - 测试分层:不同层级的测试用对应注解:
@DataJpaTest测试Repository层,@WebMvcTest测试Controller层,@SpringBootTest用于集成测试。 - Mockito使用:测试Controller时,通过
@MockBean模拟Repository,避免依赖真实数据库,专注测试Controller的逻辑是否正确调用依赖并返回结果。
内容的提问来源于stack exchange,提问作者ross geller
相关产品推荐
相关产品推荐

