使用JUnit和Mockito测试Controller时遇NullPointerException求助
解决JUnit+Mockito测试Controller时的NullPointerException问题
刚接触JUnit测试遇到空指针太正常啦,我来帮你捋清楚问题根源和解决办法:
你遇到的java.lang.NullPointerException,本质原因是Controller里的depService字段没有被正确初始化。真实环境中你用@Autowired让Spring自动注入DepartmentService,但测试环境下要么没启动Spring容器,要么没给Controller提供mock的服务实例,导致调用depService.findD...()时它是null,自然就抛出空指针了。
下面给你两种最常用的解决方案,你可以根据测试需求选择:
方案一:纯Mockito快速测试(不启动Spring容器)
这种方式适合只测试Controller的业务逻辑,不需要加载整个Spring上下文,测试速度很快。核心思路是用Mockito模拟DepartmentService,再把这个mock对象注入到Controller实例中:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) // 启用Mockito的JUnit扩展支持 public class DepartmentControllerTest { @Mock // 告诉Mockito要模拟这个服务类 private DepartmentService depService; @InjectMocks // 自动把mock的服务注入到Controller实例中 private DepartmentController departmentController; @Test public void testFindDeptId() { // 1. 准备测试用的mock数据 Department mockDepartment = new Department(); mockDepartment.setId(1L); mockDepartment.setDeptName("研发部"); // 替换成你实际的字段名 // 2. 设定mock行为:当调用depService的findD...方法时,返回我们准备的mock对象 when(depService.findD...()).thenReturn(mockDepartment); // 3. 调用Controller的目标方法 Department result = departmentController.findDeptId(); // 4. 验证结果是否符合预期 assertNotNull(result, "返回的部门对象不能为null"); assertEquals(1L, result.getId(), "部门ID不匹配"); assertEquals("研发部", result.getDeptName(), "部门名称不匹配"); } }
方案二:结合Spring Boot Test测试HTTP接口
如果你想完整测试HTTP请求流程(比如验证请求路径、响应状态码、返回的JSON格式等),可以用这种方式:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @SpringBootTest // 启动Spring上下文 @AutoConfigureMockMvc // 自动配置MockMvc用来模拟HTTP请求 public class DepartmentControllerHttpTest { @Autowired private MockMvc mockMvc; // 用来模拟发送HTTP请求 @MockBean // 用mock的服务替换Spring容器里的真实DepartmentService private DepartmentService depService; @Test public void testLoadDeptEndpoint() throws Exception { // 准备mock数据 Department mockDept = new Department(); mockDept.setId(1L); mockDept.setDeptName("市场部"); // 设定mock服务的行为 when(depService.findD...()).thenReturn(mockDept); // 模拟发送GET请求,并验证响应 mockMvc.perform(get("/api.spacestudy.com/SpaceStudy/LoadDept") .header("Origin", "http://localhost:4200")) // 带上跨域所需的Origin头 .andExpect(status().isOk()) // 验证响应状态码是200 .andExpect(jsonPath("$.id").value(1L)) // 验证返回JSON里的id字段 .andExpect(jsonPath("$.deptName").value("市场部")); // 验证部门名称 } }
几个关键注意事项
- 绝对不要直接用
new DepartmentController()创建实例!这样depService永远是null,必须用Mockito的@InjectMocks或者Spring的@MockBean来处理依赖注入 - 确保你mock的方法签名和真实的
depService.findD...()完全一致,包括参数、返回值,否则Mockito不会拦截这个调用,可能还是会执行真实方法(如果没mock的话就会报错) - 如果你用的是JUnit 4,记得把
@ExtendWith(MockitoExtension.class)换成@RunWith(MockitoJUnitRunner.class)
内容的提问来源于stack exchange,提问作者SpringUser
相关产品推荐
相关产品推荐

