I want to test my WebSocket application.
The test class:
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(
classes = {WebConfig.class, WebSocketConfig.class}
@DirtiesContext
public class IntegrationTest {
@Autowired
public EmbeddedWebApplicationContext server;
@Test
...
}
The WebConfig class:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
public final WebSocketService webSocketService;
@Autowired
public WebConfig(WebSocketService webSocketService) {
this.webSocketService = webSocketService;
}
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.setPort(1234);
tomcat.setContextPath("/test");
return tomcat;
}
}
And the WebSocketConfig class:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
public WebSocketConfig() {}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(webSocketHandler(), "ws")
.setAllowedOrigins("*")
}
@Bean
public WebSocketHandler webSocketHandler() {
return new WebsocketHandler(webSocketService());
}
@Bean
publicWebSocketService webSocketService() {
return newWebSocketServiceImpl();
}
}
When I start the test, Tomcat is starting and is listening at the specified Port 1234
. But I can't connect a websocket client. The WebSocketConfig is called. But I think the websocket mapping doesn't work. Did I forget anything to configure?
When I am starting the test with the application class (WebSocketApp.class
) which is annotated with @SpringBootApplication
, then the websocket mapping works fine.
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(
classes = {WebSocketApp.class}
@DirtiesContext
public class IntegrationTest {
@Autowired
public EmbeddedWebApplicationContext server;
@Test
...
}
The WebSocketApp also uses the same configurations.
I assume the second approach is working, because the @EnableWebSocket
is used. And when I don't take the WebSocketApp.class (annotated with @SpringBootApplication
) the @EnableWebSocket
will be ignored.
Does anybody have an idea to get the test running? How can I enable websockets manually without annotations?
EDIT:
I found out, that there the TomcatEmbeddedContext
is using a default servlet mapping instead a dispatcherServlet
mapping. Is it possible to set this type of mapping?
I found a solution. In test configuration Spring didn't bootstrap the websocket container and the servlet mapping.
I had to add some additional configurations:
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public ServletRegistrationBean dispatchServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet(), "/");
registration
.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
return registration;
}
And to EmbeddedServletContainerFactory
bean:
tomcat.addContextCustomizers((TomcatContextCustomizer) context ->
context.addServletContainerInitializer(new WsSci(), null));