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

Spring Boot测试中Mock控制器触发NullPointerException问题排查

问题分析与解决:Spring Boot测试Mock控制器引发的NullPointerException

问题场景

创建Spring Boot测试验证某端点,应用处于运行状态,业务层需调用外部端点,因此创建Mock控制器,但测试时抛出NullPointerException。

错误日志

2023-03-19 00:21:22.082  INFO 13788 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring TestDispatcherServlet 'dispatcherServlet'
2023-03-19 00:21:22.082  INFO 13788 --- [nio-8080-exec-1] o.s.t.web.servlet.TestDispatcherServlet  : Initializing Servlet 'dispatcherServlet'
2023-03-19 00:21:22.087 DEBUG 13788 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : 1 mappings in 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping'
2023-03-19 00:21:22.091 DEBUG 13788 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: none
2023-03-19 00:21:22.094 DEBUG 13788 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: none
2023-03-19 00:21:22.095 DEBUG 13788 --- [nio-8080-exec-1] o.s.t.web.servlet.TestDispatcherServlet  : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2023-03-19 00:21:22.095  INFO 13788 --- [nio-8080-exec-1] o.s.t.web.servlet.TestDispatcherServlet  : Completed initialization in 13 ms
2023-03-19 00:21:22.109 DEBUG 13788 --- [nio-8080-exec-1] o.s.t.web.servlet.TestDispatcherServlet  : POST "/blueprint/callback", parameters={}
2023-03-19 00:21:22.116 DEBUG 13788 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.vmware.tango.integration.mock.MockBlueprintController#callback()
2023-03-19 00:21:22.116 DEBUG 13788 --- [nio-8080-exec-1] o.s.t.web.servlet.TestDispatcherServlet  : Failed to complete request: java.lang.NullPointerException
2023-03-19 00:21:22.119 ERROR 13788 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
    at org.springframework.test.web.servlet.TestDispatcherServlet.getHandler(TestDispatcherServlet.java:125)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1047)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:696)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)

相关代码

测试类

@Log4j2
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { WebSecurityConfig.class,  WebConfiguration.class },
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@AutoConfigureWebClient
public class WorkflowTest {
}

WebConfiguration类

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

}

WebSecurityConfig类

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").permitAll()
                .and()
                .csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/**");
    }

}

注:测试类位于独立模块中

问题原因与解决方法

核心原因

日志显示请求已映射到MockBlueprintController#callback(),但TestDispatcherServlet.getHandler()方法触发空指针。主要有两个问题:

  1. WebSecurity配置过度忽略请求:web.ignoring().antMatchers("/**")会让Spring Security完全绕过所有请求的处理流程,导致TestDispatcherServlet无法找到合法的处理器映射。
  2. Mock控制器未被容器扫描:测试类的@SpringBootTest仅指定了Web相关配置类,未包含MockBlueprintController,导致容器未初始化该控制器实例,映射无效。

解决步骤

  1. 修正WebSecurity忽略规则:
    移除全局忽略配置,仅忽略静态资源等不需要拦截的路径:

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**", "/css/**", "/js/**");
    }
    
  2. 确保Mock控制器被扫描:
    在测试类的@SpringBootTest中添加MockBlueprintController类,或者通过@ComponentScan扫描其所在包:

    // 方式1:直接指定类
    @SpringBootTest(classes = { WebSecurityConfig.class, WebConfiguration.class, MockBlueprintController.class },
            webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    
    // 方式2:扫描包
    @ComponentScan(basePackages = "com.vmware.tango.integration.mock")
    
  3. 验证Mock控制器注解:
    确保MockBlueprintController添加了@RestController或@Controller,且请求映射注解配置正确:

    @RestController
    @RequestMapping("/blueprint")
    public class MockBlueprintController {
        @PostMapping("/callback")
        public ResponseEntity<Void> callback() {
            // Mock业务逻辑
            return ResponseEntity.ok().build();
        }
    }
    
  4. 优化测试方式:
    若测试运行中的真实应用端点,可使用TestRestTemplate配合随机端口发送请求:

    @Autowired
    private TestRestTemplate restTemplate;
    
    @LocalServerPort
    private int port;
    
    @Test
    public void testCallbackEndpoint() {
        String url = "http://localhost:" + port + "/blueprint/callback";
        ResponseEntity<Void> response = restTemplate.postForEntity(url, null, Void.class);
        assertEquals(HttpStatus.OK, response.getStatusCode());
    }
    

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:43:10