Spring Boot测试启动失败:缺少ServletWebServerFactory bean,求排查方案
你遇到的问题核心是Spring Boot测试上下文没有加载Web服务器相关的自动配置——虽然你已经引入了spring-boot-starter-tomcat依赖,但配置加载逻辑出现了偏差,具体分析和解决方案如下:
问题根源
你在@SpringBootTest注解中指定了classes = { WebsocketSourceConfiguration.class, WebSocketSourceIntegrationTests.class },这会让Spring只加载这两个类及其关联的配置。但Spring Boot的Web服务器自动配置(比如ServletWebServerFactoryAutoConfiguration)并没有被包含进来:这些自动配置类通常是通过带有@SpringBootApplication的主启动类触发加载的,而你的测试上下文里没有引入这个主类,导致无法创建ServletWebServerFactory bean。
解决方案
1. 引入Spring Boot主启动类到测试上下文
最直接且推荐的方式是把你项目中带有@SpringBootApplication注解的主启动类,添加到@SpringBootTest的classes参数中:
@RunWith(SpringRunner.class) @SpringBootTest( classes = { YourMainApplication.class, WebsocketSourceConfiguration.class, WebSocketSourceIntegrationTests.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "websocket.path=/some_websocket_path", "websocket.allowedOrigins=*", "spring.cloud.stream.default-binder=kafka" } ) public class WebSocketSourceIntegrationTests { // ... 其他代码 }
YourMainApplication是你项目的主启动类,它会自动启用Spring Boot的自动配置机制,包括Web服务器的自动配置,这样ServletWebServerFactory bean就会被正确创建。
2. 显式引入Web服务器自动配置类(备选方案)
如果你不想引入主启动类,可以直接把Web服务器相关的自动配置类加入classes参数:
@SpringBootTest( classes = { ServletWebServerFactoryAutoConfiguration.class, WebsocketSourceConfiguration.class, WebSocketSourceIntegrationTests.class }, // 其他参数不变 )
不过这种方式不够完整,可能会遗漏其他必要的自动配置,所以优先推荐第一种方案。
3. 修复硬编码的端口问题
另外注意到你硬编码了port = "8080",但你配置了webEnvironment = RANDOM_PORT,这会导致测试实际使用的随机端口和代码里的8080不一致,建议用@LocalServerPort注解注入实际端口:
@LocalServerPort private int port; // 自动注入随机生成的端口 @Test public void testWebSocketStreamSource() throws IOException, InterruptedException { StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); ClientWebSocketContainer clientWebSocketContainer = new ClientWebSocketContainer(webSocketClient, "ws://localhost:" + port + "/some_websocket_path"); // ... 其他代码 }
4. 检查配置类是否排除了Web自动配置
最后确认WebsocketSourceConfiguration类有没有通过@EnableAutoConfiguration(exclude = ...)或者@SpringBootApplication(exclude = ...)排除了Web相关的自动配置类,如果有的话,需要移除这些排除项。
内容的提问来源于stack exchange,提问作者Devas

