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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:22:17