在运行SpringBoot单元测试时,出现以下报错
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'serverEndpointExporter' defined in class path resource [XXX/XXX/WebSocketConfig.class]: Invocation of init method failed;
nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
导致启动单元测试失败,遇到这类错误,要从末尾往前看,往往末尾的一个报错是根本原因。
这里可以看到是因为javax.websocket.server.ServerContainer不可用,抛出了一个IllegalStateException。
很明显它是一个websocket包下的类,那么应该就和websocket拖不了干系。
通过查阅资料得知,这是因为在启动单元测试时,SpringBootTest不会启动服务器,WebSocket自然也就没有启动,但是在代码里又配置了WebSocket,就会出错。
解决方法:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
在SprintBootTest里加上一段配置,指定一个Web环境,值为随机端口。
解析:
点进SpringBootTest的注解可以看到这样一段代码:
/**
* The type of web environment to create when applicable. Defaults to
* {@link WebEnvironment#MOCK}.
* @return the type of web environment
*/
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
可以得知这个webEnvironment是指明运行时创建的web环境。
关于WebEnvironment这个类的定义在下面:
/**
* An enumeration web environment modes.
*/
enum WebEnvironment {
/**
* Creates a {@link WebApplicationContext} with a mock servlet environment if
* servlet APIs are on the classpath, a {@link ReactiveWebApplicationContext} if
* Spring WebFlux is on the classpath or a regular {@link ApplicationContext}
* otherwise.
*/
MOCK(false),
/**
* Creates a web application context (reactive or servlet based) and sets a
* {@code server.port=0} {@link Environment} property (which usually triggers
* listening on a random port). Often used in conjunction with a
* {@link LocalServerPort} injected field on the test.
*/
RANDOM_PORT(true),
/**
* Creates a (reactive) web application context without defining any
* {@code server.port=0} {@link Environment} property.
*/
DEFINED_PORT(true),
/**
* Creates an {@link ApplicationContext} and sets
* {@link SpringApplication#setWebApplicationType(WebApplicationType)} to
* {@link WebApplicationType#NONE}.
*/
NONE(false);
private final boolean embedded;
WebEnvironment(boolean embedded) {
this.embedded = embedded;
}
/**
* Return if the environment uses an {@link ServletWebServerApplicationContext}.
* @return if an {@link ServletWebServerApplicationContext} is used.
*/
public boolean isEmbedded() {
return this.embedded;
}
}
这是一个内部枚举类,包含了四个值:MOCK、RANDOM_PORT、DEFINED_PORT和NONE,我们这里使用RANDOM_PORT枚举值随机端口,MOCK代表你配置文件里指明的端口,DEFINED_PORT代表你可以设置端口号。
如果您觉得文章写得还不错,不妨点个赞。如果有什么疑惑或者不对的地方,可以留下评论,看到我会及时回复的。所有关注都会回关!