Testing Websockets with Spring

Reading time ~1 minute

In the last week, I had a problem after including some new libraries in the project that I was working on. There was no exception occurring, but the Web Sockets stopped to work.

Unfortunately, we just realized the problem after some days. This gave me some hours of work (and some gray hairs), trying to figure out manually what commit breaks the web socket. Actually, it was my mistake, I didn’t write any integration test for the Web Socket.

After discovering the problem. (an integration problem with the lib spring-cloud-sleuth), I decided to write a test for it. I don’t want to have the same problem again!

I had never written tests for Web Sockets before, and I didn’t find any clear and good example for it. Then, I decided to share my solution here, maybe it will help someone that needs it.

This is the websocket configuration using Spring:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry
                .addEndpoint("/websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    }
}s

And here I put the test using Stomp Client. Basically, the test connects to the Web Socket, then subscribes to the topic and sends a message. I used the class BlockingQueue, in order to wait for the asynchronous response.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
@WebIntegrationTest
public class WebSocketTest {

    static final String WEBSOCKET_URI = "ws://localhost:8080/websocket";
    static final String WEBSOCKET_TOPIC = "/topic";

    BlockingQueue<String> blockingQueue;
    WebSocketStompClient stompClient;

    @Before
    public void setup() {
        blockingQueue = new LinkedBlockingDeque<>();
        stompClient = new WebSocketStompClient(new SockJsClient(
                asList(new WebSocketTransport(new StandardWebSocketClient()))));
    }

    @Test
    public void shouldReceiveAMessageFromTheServer() throws Exception {
        StompSession session = stompClient
                .connect(WEBSOCKET_URI, new StompSessionHandlerAdapter() {})
                .get(1, SECONDS);
        session.subscribe(WEBSOCKET_TOPIC, new DefaultStompFrameHandler());

        String message = "MESSAGE TEST";
        session.send(WEBSOCKET_TOPIC, message.getBytes());

        Assert.assertEquals(message, blockingQueue.poll(1, SECONDS));
    }

    class DefaultStompFrameHandler implements StompFrameHandler {
        @Override
        public Type getPayloadType(StompHeaders stompHeaders) {
            return byte[].class;
        }

        @Override
        public void handleFrame(StompHeaders stompHeaders, Object o) {
            blockingQueue.offer(new String((byte[]) o));
        }
    }
}

Lesson learned

Always write integration tests. It can prevent bugs when you upgrade libraries, or when you include new ones. It also can save some hours and headaches in the future.

If you want, you can clone the complete project from my github:

https://github.com/rafaelhz/testing-spring-websocket.git

If you have some doubts, or have some suggestion to improve this code, please let me know.

That’s it for today friends, until next time!

Spike and TDD - Exploring the unknown

Spikes and TDD - Exploring the unknown Continue reading

Bundling Js modules with WebPack

Published on April 25, 2016

Simplifying your code with Lodash

Published on March 22, 2016