SpringBoot单元测试报IllegalStateException: Failed to load ApplicationContext错误的解决方法
报错描述
在使用SpringBootTest单元测试时 出现非法状态异常
一直提示无法加载应用上下文 是由于我们使用了WebSocket在测试环境启动时嵌入的Servlet容器导致
报错信息部分内容如下
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:124) [spring-boot-test-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) [spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance
Caused by: java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:124) ~[spring-boot-test-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.2.7.RELEASE.jar:5.2.7.RELEASE]
... 65 common frames omitted
Caused by: java.lang.NullPointerException: null
at com.etjava.config.StartupRunner.loadData(StartupRunner.java:61) ~[classes/:na]
at com.etjava.config.StartupRunner.run(StartupRunner.java:56) ~[classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784) ~[spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
... 70 common frames omitted
java.lang.IllegalStateException: Failed to load ApplicationContext
解决方案
将@SpringBootTest的属性webEnvironment改为SpringBootTest.WebEnvironment.RANDOM_PORT即可
例如:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
解释:
@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即可
