使用Mockito Mock接口时触发NullPointerException问题排查
问题分析与解决方案
核心问题1:@Autowired MockMvc 空指针
你用@WebMvcTest(IMnJobManager.class)时,Spring Boot的@WebMvcTest注解需要传入控制器的实现类(也就是CMnJobManager),而非接口IMnJobManager。这个注解的作用是加载指定控制器到测试上下文,传接口的话,容器找不到对应的控制器实例,无法创建MockMvc,导致@Autowired拿到null,调用mockMvc.perform()时触发空指针。
核心问题2:standaloneSetup 导致404
你用MockMvcBuilders.standaloneSetup(allWorkFlows).build()时,传入的是IMnAllWorkFlows的Mock对象,而非控制器CMnJobManager的实例。standaloneSetup需要传入处理请求的控制器实例,否则Spring找不到对应的请求映射,返回404。就算传入控制器,也要把Mock依赖注入进去,不然控制器里的依赖还是null,无法正常工作。
正确的测试写法
方式1:用@WebMvcTest + @MockBean(推荐)
利用Spring测试上下文自动注入依赖,写法更简洁:
@WebMvcTest(CMnJobManager.class) public class CMnJobManagerTest { @Autowired private MockMvc mockMvc; // 用@MockBean为控制器的所有依赖创建Mock,Spring会自动注入到控制器中 @MockBean private IMnAllWorkFlows allWorkFlows; @MockBean private IMnWorkflowService workflowService; @MockBean private IMnTemporalServiceClient temporalServiceClient; @MockBean private IMnWorkflowHistoryService workflowHistoryService; @MockBean private IMnSearchAttributeService searchAttributeService; @MockBean private IMnS3Tenant s3Tenant; @MockBean private HttpServletRequest request; @MockBean private CMnCustomMetricService customMetricService; @Test public void testExample() throws Exception { // 配置Mock方法的返回值 Mockito.when(allWorkFlows.getAllTenants()) .thenReturn(Arrays.asList("modn-ops")); mockMvc.perform(get("/v1/tenant")) .andExpect(status().isOk()) // 接口返回的是List,用containsString匹配,或用jsonPath断言更准确 .andExpect(content().string(org.hamcrest.Matchers.containsString("modn-ops"))) .andDo(print()); } }
方式2:用standaloneSetup手动初始化
如果不想依赖Spring上下文,手动构建控制器和MockMvc:
public class CMnJobManagerTest { @Test public void testExample() throws Exception { // 手动创建所有依赖的Mock IMnAllWorkFlows allWorkFlows = Mockito.mock(IMnAllWorkFlows.class); IMnWorkflowService workflowService = Mockito.mock(IMnWorkflowService.class); IMnTemporalServiceClient temporalServiceClient = Mockito.mock(IMnTemporalServiceClient.class); IMnWorkflowHistoryService workflowHistoryService = Mockito.mock(IMnWorkflowHistoryService.class); IMnSearchAttributeService searchAttributeService = Mockito.mock(IMnSearchAttributeService.class); IMnS3Tenant s3Tenant = Mockito.mock(IMnS3Tenant.class); HttpServletRequest request = Mockito.mock(HttpServletRequest.class); CMnCustomMetricService customMetricService = Mockito.mock(CMnCustomMetricService.class); // 创建控制器实例,传入所有Mock依赖 CMnJobManager controller = new CMnJobManager(allWorkFlows, workflowService, temporalServiceClient, workflowHistoryService, searchAttributeService, s3Tenant); // 手动注入@Autowired字段(构造器未处理的依赖) controller.request = request; controller.customMetricService = customMetricService; // 初始化MockMvc,传入控制器实例 MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); // 配置Mock方法 Mockito.when(allWorkFlows.getAllTenants()).thenReturn(Arrays.asList("modn-ops")); mockMvc.perform(get("/v1/tenant")) .andExpect(status().isOk()) .andExpect(content().string(org.hamcrest.Matchers.containsString("modn-ops"))) .andDo(print()); } }
关键注意点
@WebMvcTest必须传控制器实现类,不能传接口- 手动创建的Mock必须注入到控制器中,否则控制器用的是真实依赖(或null),Mock逻辑不会生效
- 如果接口返回集合,不要直接用
content().string("modn-ops")断言,应该用jsonPath或containsString匹配
内容的提问来源于stack exchange,提问作者Swaraj Shekhar
相关产品推荐
相关产品推荐

