如何在 Spring Boot 中接收来自 Websocket 单元测试的响应
How to Receive Response from Websocket Unit Test in Springboot
我是 websockets 的新手,我正在尝试编写单元测试。
我的单元测试运行良好,但有以下两个问题
不知道为什么,但它迫使我期望相同的对象作为输入(即 WebSocketRequestData)发送到 websocket,而不是来自 websocket 的实际响应,即 WebSocketData
它 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
我是 websockets 的新手,我正在尝试编写单元测试。
我的单元测试运行良好,但有以下两个问题
不知道为什么,但它迫使我期望相同的对象作为输入(即 WebSocketRequestData)发送到 websocket,而不是来自 websocket 的实际响应,即 WebSocketData
它 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