SpringBoot单元测试报java.lang.IllegalStateException: Failed to load ApplicationContext错误的解决方法

大致原因:使用了WebSocket使得在测试环境也得需要启动嵌入式的Servlet容器

解决方案:将@SpringBootTest的属性webEnvironment改为SpringBootTest.WebEnvironment.RANDOM_PORT即可

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

以下为详细解释:

在使用单元测试时报以下

java.lang.IllegalStateException: Failed to load ApplicationContext

一开始很疑惑,因为我之前使用过单元测试是能使用的,然后看了看完整的报错信息

java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@19bfbe28 testClass = com.example.demo.service.impl.TeamServiceImplTest, locations = [], classes = [com.example.demo.DemoApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@537f60bf, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@229c6181, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@d86a6f, org.springframework.boot.test.web.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@6e6f2380, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@53fe15ff, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@4be29ed9, org.springframework.boot.test.context.SpringBootTestAnnotation@88aa156c], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]

	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:163)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serviceEndpointExporter' defined in class path resource [com/example/demo/config/WebSocketConfiguration.class]: jakarta.websocket.server.ServerContainer not available
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
	at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
	at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1463)
	at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:553)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)

似乎是使用了WebSocket之后产生的问题,在网上查了查资料才知道,@SpringBootTest的webEnvironment属性

默认是MOCK值,它会使用Mock的Servlet环境,而不会启动嵌入式的Servlet容器,这意味着不能进行真实网络请求。当将属性值改为RANDOM_PORT时,它会启动嵌入式的Servlet容器(如Tomcat),并在一个随机端口上监听,这在WebSocket测试是必要的。

WebSocket是一种在单个TCP连接上进行全双工通信的协议。这意味着客户端和服务器之间需要持续的、双向的数据流。在单元测试中,如果使用了Mock的Servlet环境(即webEnvironment = MOCK),则不会启动嵌入式的Servlet容器,因此WebSocket连接无法建立。

而设置webEnvironment = RANDOM_PORT时,Spring Boot会启动一个嵌入式的Servlet容器(如Tomcat),并在一个随机端口上监听。这允许你的测试代码通过WebSocket客户端连接到这个容器,从而进行实际的网络通信测试。这是WebSocket集成测试所必需的。

所以我们只需要将webEnvironment webEnvironment属性改SpringBootTest.WebEnvironment.RANDOM_PORT即可

### 问题分析 在 Spring Boot 单元测试中出现 `java.lang.IllegalStateException: Failed to load ApplicationContext` 的错误,通常表明测试环境无法正确加载 Spring 应用上下文。这种问题可能由多种原因引起,包括配置错误、依赖冲突或测试类未正确指定应用上下文。 以下是一些常见的解决方案和改进建议[^1]。 --- ### 解决方案 #### 1. 指定明确的应用上下文 如果测试类没有明确指定应用上下文的入口类(如 `@SpringBootApplication` 注解的主类),可能会导致上下文加载失败。可以通过以下方式解决: ```java @SpringBootTest(classes = AdminApplication.class) @RunWith(SpringRunner.class) public class SpringBoot1ApplicationTests { @Autowired private Person person; @Test public void contextLoads() { System.out.println(person); } } ``` 这里通过 `@SpringBootTest(classes = AdminApplication.class)` 明确指定了应用上下文的入口类[^2]。 --- #### 2. 配置 Web 环境 根据测试需求,可以选择不同的 `WebEnvironment` 类型。如果测试需要启动嵌入式容器(例如测试控制器或 WebSocket),可以设置为 `RANDOM_PORT`: ```java @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @RunWith(SpringRunner.class) public class SpringBoot1ApplicationTests { @Autowired private Person person; @Test public void contextLoads() { System.out.println(person); } } ``` 当设置为 `RANDOM_PORT` 时,Spring Boot 会启动一个嵌入式的 Servlet 容器,并在随机端口上监听请求[^4]。 如果测试不需要启动实际的 Web 环境(例如仅测试服务层逻辑),可以使用 `MOCK`: ```java @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @RunWith(SpringRunner.class) public class SpringBoot1ApplicationTests { @Autowired private Person person; @Test public void contextLoads() { System.out.println(person); } } ``` --- #### 3. 检查依赖冲突 某些情况下,依赖冲突可能导致上下文加载失败。例如,Druid 数据库连接池的过滤器可能会抛出 `NullPointerException`[^3]。可以通过以下方式排查: - 使用 Maven 或 Gradle 检查依赖树,确保没有版本冲突。 - 如果使用了 Druid 连接池,检查其版本是否与 Spring Boot 兼容,并确保正确配置了过滤器。 --- #### 4. 确保配置文件正确加载 如果测试需要加载特定的配置文件(如 `application-test.yml`),可以通过 `@ActiveProfiles` 指定活动的配置文件: ```java @SpringBootTest @ActiveProfiles("test") @RunWith(SpringRunner.class) public class SpringBoot1ApplicationTests { @Autowired private Person person; @Test public void contextLoads() { System.out.println(person); } } ``` --- #### 5. 捕获详细的错误日志 如果上述方法仍未解决问题,可以通过启用调试日志捕获更详细的错误信息: ```properties logging.level.org.springframework=DEBUG ``` 将此配置添加到 `application.properties` 或 `application.yml` 文件中,以便更好地定位问题。 --- ### 示例代码 以下是综合以上解决方案的一个完整示例: ```java @SpringBootTest(classes = AdminApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK) @ActiveProfiles("test") @RunWith(SpringRunner.class) public class SpringBoot1ApplicationTests { @Autowired private Person person; @Test public void contextLoads() { assertNotNull(person); System.out.println(person); } } ``` --- ###
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值