如何在 Spring Boot 中接收来自 Websocket 单元测试的响应

How to Receive Response from Websocket Unit Test in Springboot

我是 websockets 的新手,我正在尝试编写单元测试。

我的单元测试运行良好,但有以下两个问题

  1. 不知道为什么,但它迫使我期望相同的对象作为输入(即 WebSocketRequestData)发送到 websocket,而不是来自 websocket 的实际响应,即 WebSocketData

  2. 它 returns 结果是一个空对象,因此它通过了 NotNull 断言。

谁能帮我解开这个困惑!

还有什么是在单元测试中从我的 websocket 获得响应的正确方法?

这是我的 websocketTest 的代码 Class

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ServerWebSocketTest {

@LocalServerPort
private Integer port;

static final String WEBSOCKET_TOPIC = "/user/locationrealtimedata/item" ;

BlockingQueue<WebSocketRequestData> blockingQueue;
WebSocketStompClient stompClient;

@BeforeEach
public void setup() {

    blockingQueue = new LinkedBlockingDeque<>();
    stompClient = new WebSocketStompClient(new SockJsClient(
            asList(new WebSocketTransport(new StandardWebSocketClient()))));
    
    stompClient.setMessageConverter(new MappingJackson2MessageConverter());

}

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

    WebSocketRequestData webSocketRequestData = new WebSocketRequestData();
    webSocketRequestData.setUserId("usr-1");
    webSocketRequestData.setAccountId("acc-1");
    webSocketRequestData.setGroupId("grp-1");
    session.send("/wsconn/start", webSocketRequestData);
    WebSocketRequestData responseObj = blockingQueue.poll(15, TimeUnit.SECONDS);
    Assertions.assertNotNull(responseObj);

}

class DefaultStompFrameHandler extends StompSessionHandlerAdapter{   
    @Override
    public Type getPayloadType(StompHeaders stompHeaders) {
        return WebSocketRequestData.class;
    }

    @Override
    public void handleFrame(StompHeaders stompHeaders, Object o) {
        blockingQueue.offer((WebSocketRequestData) o); // instead of **WebSocketData** it forces me to add casting for **WebSocketRequestData**
    }


    @Override
    public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
        exception.printStackTrace();
    }


}

private String getWsPath() {
    return String.format("ws://localhost:%d/location_services/locationrealtimedata", port);
}

}

提前致谢

您不会被迫对输入和响应类型使用相同的 Java class。

请求类型是您在 session.send("/endpoint", payload); 中使用的类型,在您的情况下是 WebSocketRequestData:

WebSocketRequestData webSocketRequestData = new WebSocketRequestData();
webSocketRequestData.setUserId("usr-1");
webSocketRequestData.setAccountId("acc-1");
webSocketRequestData.setGroupId("grp-1");
session.send("/wsconn/start", webSocketRequestData);

在使用消息时,您指定在实施 StompFrameHandler 和覆盖 getPayloadType.

时期望的实际响应类型

所以不要实现 StompSessionHandlerAdapter,而是使用 StompFrameHandler 接口并按如下方式实现它:

class DefaultStompFrameHandler extends StompSessionHandlerAdapter{   
    @Override
    public Type getPayloadType(StompHeaders stompHeaders) {
        return WebSocketData.class; // or any other class your expect
    }

    @Override
    public void handleFrame(StompHeaders stompHeaders, Object o) {
        blockingQueue.offer((WebSocketData) o); 
    }

    @Override
    public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
        exception.printStackTrace();
    }

}

还要确保您的 BlockingQueue 使用的类型正确 BlockingQueue<WebSocketData> blockingQueue