Search code examples
javaspringspring-bootspring-websocketspring-boot-test

SpringBootTest @EnabledWebSocket ignored


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?


Solution

  • 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));