在SpringBoot项目中,增加WebSocket功能之后(SpringBoot使用WebSocket实现前后端消息推送)执行单元测试,发现会报错。
java.lang.IllegalStateException: Failed to load ApplicationContext
查看异常栈信息
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'serverEndpointExporter' defined in class path resource [com/lqc/app/config/WebSocketConfig.class]:
Invocation of init method failed; nested exception is java.lang.IllegalStateException:
javax.websocket.server.ServerContainer not available
大意是,在创建WebSocket的ServerEndpointExporter这个bean的时候创建失败,原因是找不到javax.websocket.server.ServerContainer这个接口的实现类,但是我们正常启动项目都能启动起来,为啥会没有这个类呢?
查看@SpringBootTest注解的内容,我们发现默认的WebEnvironment是MOCK类型,而MOCK的embedded值为false。也就是说,默认的单元测试是不真正启动web容器(嵌入的tomcat),而ServerEndpointExporter这个bean依赖的javax.websocket.server.ServerContainer
这个接口的实现类org.apache.tomcat.websocket.server.WsServerContainer
恰好就在web容器中。
因此默认的MOCK类型由于不启动web容器继而导致ServerEndpointExporter创建失败进而导致单元测试报错。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith({SpringExtension.class})
public @interface SpringBootTest {
@AliasFor("properties")
String[] value() default {};
@AliasFor("value")
String[] properties() default {};
String[] args() default {};
Class<?>[] classes() default {};
SpringBootTest.WebEnvironment webEnvironment() default SpringBootTest.WebEnvironment.MOCK;
public static enum WebEnvironment {
MOCK(false),
RANDOM_PORT(true),
DEFINED_PORT(true),
NONE(false);
private final boolean embedded;
private WebEnvironment(boolean embedded) {
this.embedded = embedded;
}
public boolean isEmbedded() {
return this.embedded;
}
}
}
问题原因找到了,解决问题的办法也很简单,我们手动指定一下WebEnvironment即可。在@SpringBootTest上增加一个参数,代码如下:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
单元测试即可正常运行。