SpringBoot2.0整合WebSocket后JUnit单元测试报错:javax.websocket.server.ServerContainer not available

本文介绍了一种解决WebSocket在单元测试中报错的方法。通过在单元测试类上使用@SpringBootTest注解,指定启动类和环境为DEFINED_PORT,可以提供一个servlet环境,使WebSocket能够正常初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

整个程序运行时是不报错的,但是单元测试就会报错。
解决办法:
在单元测试的类上加上注解:
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
这里的Application是你SpringBoot启动类的类名。

这里注解的作用是提供一个servlet环境,好让websocket能够初始化。

java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:341) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:346) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:341) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743) at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742) at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:340) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:263) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:256) at java.util.Optional.orElseGet(Optional.java:267) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:255) at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:108) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:107) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:71) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75) at java.util.ArrayList.forEach(ArrayList.java:1257) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at java.util.ArrayList.forEach(ArrayList.java:1257) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248) at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211) at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:231) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExporter' defined in class path resource [com/niwenn/consumer/config/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ... 65 more Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available at org.springframework.util.Assert.state(Assert.java:76) at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterPropertiesSet(ServerEndpointExporter.java:107) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790) ... 81 more
最新发布
07-17
<think>首先,用户的问题是关于Spring Boot测试中的错误:java.lang.IllegalStateException: Failed to load ApplicationContext,具体是由于WebSocket配置导致的,错误信息提到ServerContainer not available。用户引用了几个参考,这些引用描述了类似的问题,比如依赖注入失败、测试配置问题等。 关键点是用户的问题集中在WebSocketConfig上,错误是ServerContainer not available。我需要根据系统级指令来构建回答。 系统级指令: 1. 所有行内数学表达式必须使用$...$格式。 2. 独立公式必须使用$$...$$格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识。 用户问题涉及编程错误,没有数学表达式,所以我可能不需要使用LaTeX数学格式,除非在解释概念涉及公式。但为了遵守指令,如果有数学相关内容,我会用$...$或$$...$$。 用户的需求是解决Spring Boot测试中加载ApplicationContext失败的问题,具体是WebSocketConfig导致的ServerContainer not available。 参考引用: - 引用[1]:一般错误,加载ApplicationContext失败。 - 引用[2]:解决方法,提到设置webEnvironment = RANDOM_PORT,以便启动嵌入式容器进行WebSocket测试。 - 引用[3]:UnsatisfiedDependencyException,依赖注入问题。 用户的具体错误是ServerContainer not available,这通常与WebSocket配置和测试环境有关。 我的回答应该: - 结构清晰,逐步解决问题。 - 保证真实可靠。 - 使用中文。 - 在回答中引用段落添加引用标识。 - 最后生成相关问题。 步骤: 1. **理解问题**:用户在使用Spring Boot测试,遇到Failed to load ApplicationContext,原因是WebSocketConfig中ServerContainer不可用。这可能在单元测试中发生,当测试没有正确配置嵌入式服务器2. **分析原因**: - ServerContainerWebSocket API的一部分,通常由Servlet容器(如Tomcat)提供。 - 在测试中,如果测试配置不正确,容器可能没有被初始化。 - 引用[2]提到,设置webEnvironment = RANDOM_PORT可以启动嵌入式容器,这对WebSocket测试很重要。 3. **解决方案**: - 确保测试类使用@SpringBootTest注解,并设置webEnvironment。 - 使用@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)来启动随机端口的嵌入式容器。 - 检查WebSocket配置是否正确,比如@EnableWebSocket或自定义配置。 - 确保依赖项正确注入,避免UnsatisfiedDependencyException(如引用[3])。 4. **构建回答**: - 开头确认问题。 - 逐步解释原因和解决方法。 - 提供代码示例(如果适用)。 - 引用相关部分添加标识。 - 最后生成相关问题。 5. **生成相关问题**:基于主题,提出几个相关问题。 回答结构: - 介绍:简述问题。 - 原因分析:解释为什么发生。 - 解决方案:详细步骤。 - 代码示例:展示如何修改测试。 - 总结。 - 相关问题。 确保回答真实可靠:基于Spring Boot文档和常见实践。 现在,草拟回答。</think>### 解决Spring Boot测试中加载ApplicationContext失败的问题(WebSocketConfig导致ServerContainer不可用) 您在Spring Boot单元测试中遇到的错误`java.lang.IllegalStateException: Failed to load ApplicationContext`,通常是由于WebSocket配置在测试环境下未正确初始化导致的。具体错误信息`ServerContainer not available`表明测试未能启动嵌入式Servlet容器(如Tomcat),从而无法提供WebSocket所需的`ServerContainer`实例。这常见于使用`@SpringBootTest`进行集成测试,配置不当或依赖注入问题引发。下面我将逐步分析原因并提供解决方案,确保回答真实可靠(基于Spring Boot官方文档和常见实践)。 #### 问题原因分析 - **核心问题**:`ServerContainer`是WebSocket API的核心接口,由Servlet容器(如Tomcat)实现。在测试中,如果未启动嵌入式容器,`ServerContainer`将不可用,导致WebSocket配置类(如`WebSocketConfig`)初始化失败。 - **测试配置不当**:默认的`@SpringBootTest`可能使用`MOCK`环境(不启动真实容器),但WebSocket测试需要真实网络通信。引用[2]指出,设置`webEnvironment = RANDOM_PORT`可启动嵌入式容器并在随机端口监听,这是WebSocket集成测试的必要条件[^2]。 - **依赖注入失败**:如果WebSocket配置类依赖其他Bean(如Service层),但测试中未正确扫描或注入这些Bean,会引发`UnsatisfiedDependencyException`(如引用[3]所述),间接导致ApplicationContext加载失败[^3]。 - **常见触发场景**: - 测试类未显式指定`webEnvironment`参数。 - WebSocket配置类(`@Configuration`类)中使用了`ServerContainer`,但测试环境未提供容器实例。 - 项目依赖缺失(如未包含`spring-boot-starter-websocket`)。 #### 逐步解决方案 遵循以下步骤修复问题,确保测试能加载ApplicationContext并支持WebSocket。 1. **修改测试类配置,启动嵌入式容器** 在测试类上使用`@SpringBootTest`注解,并设置`webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT`。这强制Spring Boot启动嵌入式Servlet容器(如Tomcat),并在随机端口监听,从而提供`ServerContainer`实例。 ```java import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) // 关键修改:启用随机端口 public class YourWebSocketTest { // 测试方法 } ``` - **为什么有效**:`RANDOM_PORT`环境启动真实容器,支持WebSocket的底层网络通信(如WebSocket握手),而`MOCK`环境仅模拟HTTP请求,无法处理WebSocket。引用[2]证实了此方法对WebSocket测试的必要性[^2]。 2. **检查并修复WebSocket配置类** 确保您的WebSocket配置类正确启用WebSocket,并避免在测试中过早访问`ServerContainer`。 - 示例配置(`WebSocketConfig.java`): ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import javax.servlet.ServletContext; import javax.websocket.server.ServerContainer; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { private final ServletContext servletContext; public WebSocketConfig(ServletContext servletContext) { this.servletContext = servletContext; } @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // 获取ServerContainer实例(仅在容器启动后可用) ServerContainer serverContainer = (ServerContainer) servletContext.getAttribute("javax.websocket.server.ServerContainer"); if (serverContainer != null) { // 配置WebSocket端点 serverContainer.addEndpoint(YourWebSocketHandler.class); } } } ``` - **关键点**:在测试中,`ServerContainer`仅在容器启动后通过`ServletContext`获取。避免在配置类构造函数中直接访问它,否则会因容器未启动而报错。如果使用`@Autowired`注入`ServerContainer`,需确保测试环境支持(即已设置`RANDOM_PORT`)。 3. **处理依赖注入问题** 如果错误伴随`UnsatisfiedDependencyException`(如引用[3]),表明WebSocket配置依赖的其他Bean未注入。 - **解决方案**: - 在测试类上添加`@ContextConfiguration`或`@Import`,显式扫描配置类和Service Bean。 - 示例: ```java @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = {WebSocketConfig.class, YourService.class}) // 显式指定配置 public class YourWebSocketTest { // ... } ``` - 确保项目包含必要依赖(如`spring-boot-starter-websocket`),并在`pom.xml`或`build.gradle`中验证。 4. **其他验证与调试** - **启用调试日志**:运行测试添加`--debug`参数(如`mvn test -Ddebug=true`),查看详细错误堆栈,定位具体Bean初始化问题。 - **检查测试范围依赖**:确保`spring-boot-starter-test`在`test`作用域内,避免版本冲突。 - **简化测试**:临注释掉WebSocket相关代码,验证是否因其他配置导致失败。 #### 总结 通过设置`@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)`,您可以启动嵌入式容器解决`ServerContainer not available`错误。同,优化WebSocket配置类以避免过早访问容器实例,并处理依赖注入问题。如果问题持续,检查项目依赖和日志输出。引用[2]强调,这种配置是WebSocket集成测试的基础[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值